aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMauro Sardara <msardara+fdio@cisco.com>2018-12-18 11:05:49 +0000
committerGerrit Code Review <gerrit@fd.io>2018-12-18 11:05:49 +0000
commitcada1143501a48effc483e3873596c22849926b5 (patch)
tree93a1da95d69b69328a1e7d3621447797f65137c9
parent726949d76a7207694d5a1eee84ef134a8e539115 (diff)
parenta45edf23c2463ac9a4723a24792a6c5c89b1e021 (diff)
Merge "Adding gitreview config file for this branch sub project"
-rw-r--r--README.md1
-rw-r--r--libparc/.gitignore67
-rw-r--r--libparc/AUTHORS11
-rw-r--r--libparc/BASE_VERSION1
-rw-r--r--libparc/CMakeLists.txt185
-rw-r--r--libparc/LICENSE12
-rw-r--r--libparc/README.md94
-rw-r--r--libparc/cmake/Modules/CheckRealloc.cmake16
-rw-r--r--libparc/cmake/Modules/FindLibEvent.cmake60
-rw-r--r--libparc/cmake/Modules/FindLongBow.cmake57
-rw-r--r--libparc/cmake/Modules/FindUncrustify.cmake21
-rw-r--r--libparc/cmake/Modules/detectCacheSize.cmake39
-rw-r--r--libparc/cmake/Modules/version.cmake28
-rwxr-xr-xlibparc/cmake/get_version.sh20
-rw-r--r--libparc/documentation/.gitignore2
-rw-r--r--libparc/documentation/CMakeLists.txt45
-rw-r--r--libparc/documentation/DoxygenLayout.xml196
-rw-r--r--libparc/documentation/Makefile.am30
-rw-r--r--libparc/documentation/Resources/parcBuffer.grafflebin0 -> 3158 bytes
-rw-r--r--libparc/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css470
-rw-r--r--libparc/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css.map1
-rw-r--r--libparc/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.min.css5
-rw-r--r--libparc/documentation/doxygen-extras/bootstrap/css/bootstrap.css6332
-rw-r--r--libparc/documentation/doxygen-extras/bootstrap/css/bootstrap.css.map1
-rw-r--r--libparc/documentation/doxygen-extras/bootstrap/css/bootstrap.min.css5
-rw-r--r--libparc/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.eotbin0 -> 20335 bytes
-rw-r--r--libparc/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.svg229
-rw-r--r--libparc/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.ttfbin0 -> 41280 bytes
-rw-r--r--libparc/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.woffbin0 -> 23320 bytes
-rw-r--r--libparc/documentation/doxygen-extras/bootstrap/js/bootstrap.js2320
-rw-r--r--libparc/documentation/doxygen-extras/bootstrap/js/bootstrap.min.js7
-rw-r--r--libparc/documentation/doxygen-extras/bootstrap/js/npm.js13
-rw-r--r--libparc/documentation/doxygen-extras/customdoxygen.css1705
-rw-r--r--libparc/documentation/doxygen-extras/doxy-boot.js120
-rwxr-xr-xlibparc/documentation/doxygen-extras/doxygen-bootstrap.js119
-rwxr-xr-xlibparc/documentation/doxygen-extras/footer.html14
-rwxr-xr-xlibparc/documentation/doxygen-extras/header.html42
-rw-r--r--libparc/documentation/doxygen-extras/masthead.css9
-rw-r--r--libparc/documentation/examples/README.md0
-rw-r--r--libparc/documentation/images/logo_fdio.pngbin0 -> 3092 bytes
-rw-r--r--libparc/documentation/imported-stylesheet.css1
-rw-r--r--libparc/documentation/libparc.doxygen2392
-rw-r--r--libparc/documentation/libparc.doxygen.in2397
-rwxr-xr-xlibparc/examples/How To Create A Static PARC Object/main.c108
-rw-r--r--libparc/examples/How To Create A Static PARC Object/parc_MyObject.c178
-rw-r--r--libparc/examples/How To Create A Static PARC Object/parc_MyObject.h368
-rw-r--r--libparc/examples/How To Create an Object Pool/main.c35
-rw-r--r--libparc/examples/How To Create an Object Pool/parc_SimpleBufferPool.c107
-rw-r--r--libparc/examples/How To Create an Object Pool/parc_SimpleBufferPool.h100
-rw-r--r--libparc/examples/How To Extend a PARCObject/HowToExtendAPARCObject.c102
-rw-r--r--libparc/parc/CMakeLists.txt410
-rw-r--r--libparc/parc/HeaderDoc/Info.plist14
-rw-r--r--libparc/parc/HeaderDoc/Nodes.xml31
-rw-r--r--libparc/parc/HeaderDoc/adcstyle.css869
-rw-r--r--libparc/parc/HeaderDoc/gen_parc_docset.sh57
-rw-r--r--libparc/parc/HeaderDoc/headerDoc2HTML.config26
-rw-r--r--libparc/parc/HeaderDoc/parcstyle.css12
-rw-r--r--libparc/parc/algol/.gitignore4
-rw-r--r--libparc/parc/algol/Groups.dox41
-rwxr-xr-xlibparc/parc/algol/internal_parc_Event.c324
-rwxr-xr-xlibparc/parc/algol/internal_parc_Event.h168
-rw-r--r--libparc/parc/algol/parc_ArrayList.c381
-rw-r--r--libparc/parc/algol/parc_ArrayList.h577
-rwxr-xr-xlibparc/parc/algol/parc_AtomicInteger.c94
-rwxr-xr-xlibparc/parc/algol/parc_AtomicInteger.h73
-rwxr-xr-xlibparc/parc/algol/parc_Base64.c290
-rw-r--r--libparc/parc/algol/parc_Base64.h129
-rwxr-xr-xlibparc/parc/algol/parc_BitVector.c409
-rwxr-xr-xlibparc/parc/algol/parc_BitVector.h426
-rwxr-xr-xlibparc/parc/algol/parc_Buffer.c1072
-rw-r--r--libparc/parc/algol/parc_Buffer.h1665
-rw-r--r--libparc/parc/algol/parc_BufferChunker.c261
-rwxr-xr-xlibparc/parc/algol/parc_BufferChunker.h217
-rwxr-xr-xlibparc/parc/algol/parc_BufferComposer.c289
-rwxr-xr-xlibparc/parc/algol/parc_BufferComposer.h571
-rwxr-xr-xlibparc/parc/algol/parc_BufferDictionary.c146
-rwxr-xr-xlibparc/parc/algol/parc_BufferDictionary.h145
-rw-r--r--libparc/parc/algol/parc_ByteArray.c312
-rw-r--r--libparc/parc/algol/parc_ByteArray.h580
-rw-r--r--libparc/parc/algol/parc_CMacro.h49
-rwxr-xr-xlibparc/parc/algol/parc_Chunker.c75
-rwxr-xr-xlibparc/parc/algol/parc_Chunker.h250
-rwxr-xr-xlibparc/parc/algol/parc_Clock.c245
-rwxr-xr-xlibparc/parc/algol/parc_Clock.h354
-rwxr-xr-xlibparc/parc/algol/parc_Collection.h32
-rw-r--r--libparc/parc/algol/parc_Deque.c446
-rwxr-xr-xlibparc/parc/algol/parc_Deque.h465
-rwxr-xr-xlibparc/parc/algol/parc_Dictionary.c134
-rwxr-xr-xlibparc/parc/algol/parc_Dictionary.h294
-rwxr-xr-xlibparc/parc/algol/parc_DisplayIndented.c114
-rw-r--r--libparc/parc/algol/parc_DisplayIndented.h62
-rwxr-xr-xlibparc/parc/algol/parc_ElasticString.h439
-rw-r--r--libparc/parc/algol/parc_Environment.c45
-rwxr-xr-xlibparc/parc/algol/parc_Environment.h42
-rwxr-xr-xlibparc/parc/algol/parc_Event.c149
-rw-r--r--libparc/parc/algol/parc_Event.h211
-rw-r--r--libparc/parc/algol/parc_EventBuffer.c282
-rwxr-xr-xlibparc/parc/algol/parc_EventBuffer.h387
-rwxr-xr-xlibparc/parc/algol/parc_EventQueue.c353
-rw-r--r--libparc/parc/algol/parc_EventQueue.h515
-rwxr-xr-xlibparc/parc/algol/parc_EventScheduler.c171
-rw-r--r--libparc/parc/algol/parc_EventScheduler.h224
-rwxr-xr-xlibparc/parc/algol/parc_EventSignal.c127
-rwxr-xr-xlibparc/parc/algol/parc_EventSignal.h136
-rwxr-xr-xlibparc/parc/algol/parc_EventSocket.c140
-rwxr-xr-xlibparc/parc/algol/parc_EventSocket.h116
-rwxr-xr-xlibparc/parc/algol/parc_EventTimer.c128
-rwxr-xr-xlibparc/parc/algol/parc_EventTimer.h138
-rw-r--r--libparc/parc/algol/parc_Execution.c97
-rw-r--r--libparc/parc/algol/parc_Execution.h41
-rw-r--r--libparc/parc/algol/parc_File.c262
-rwxr-xr-xlibparc/parc/algol/parc_File.h278
-rw-r--r--libparc/parc/algol/parc_FileChunker.c282
-rwxr-xr-xlibparc/parc/algol/parc_FileChunker.h219
-rwxr-xr-xlibparc/parc/algol/parc_FileInputStream.c115
-rwxr-xr-xlibparc/parc/algol/parc_FileInputStream.h170
-rwxr-xr-xlibparc/parc/algol/parc_FileOutputStream.c85
-rw-r--r--libparc/parc/algol/parc_FileOutputStream.h142
-rwxr-xr-xlibparc/parc/algol/parc_Hash.c144
-rwxr-xr-xlibparc/parc/algol/parc_Hash.h341
-rwxr-xr-xlibparc/parc/algol/parc_HashCode.c49
-rwxr-xr-xlibparc/parc/algol/parc_HashCode.h94
-rwxr-xr-xlibparc/parc/algol/parc_HashCodeTable.c338
-rw-r--r--libparc/parc/algol/parc_HashCodeTable.h168
-rw-r--r--libparc/parc/algol/parc_HashMap.c666
-rwxr-xr-xlibparc/parc/algol/parc_HashMap.h622
-rwxr-xr-xlibparc/parc/algol/parc_InputStream.c57
-rwxr-xr-xlibparc/parc/algol/parc_InputStream.h117
-rwxr-xr-xlibparc/parc/algol/parc_Iterator.c159
-rw-r--r--libparc/parc/algol/parc_Iterator.h250
-rwxr-xr-xlibparc/parc/algol/parc_JSON.c404
-rwxr-xr-xlibparc/parc/algol/parc_JSON.h658
-rwxr-xr-xlibparc/parc/algol/parc_JSONArray.c185
-rwxr-xr-xlibparc/parc/algol/parc_JSONArray.h333
-rwxr-xr-xlibparc/parc/algol/parc_JSONPair.c267
-rwxr-xr-xlibparc/parc/algol/parc_JSONPair.h486
-rwxr-xr-xlibparc/parc/algol/parc_JSONParser.c181
-rwxr-xr-xlibparc/parc/algol/parc_JSONParser.h309
-rwxr-xr-xlibparc/parc/algol/parc_JSONValue.c1018
-rwxr-xr-xlibparc/parc/algol/parc_JSONValue.h938
-rwxr-xr-xlibparc/parc/algol/parc_KeyValue.c158
-rwxr-xr-xlibparc/parc/algol/parc_KeyValue.h273
-rwxr-xr-xlibparc/parc/algol/parc_KeyedElement.c78
-rwxr-xr-xlibparc/parc/algol/parc_KeyedElement.h128
-rw-r--r--libparc/parc/algol/parc_LinkedList.c705
-rw-r--r--libparc/parc/algol/parc_LinkedList.h698
-rw-r--r--libparc/parc/algol/parc_List.c277
-rw-r--r--libparc/parc/algol/parc_List.h768
-rwxr-xr-xlibparc/parc/algol/parc_Map.c20
-rwxr-xr-xlibparc/parc/algol/parc_Map.h454
-rwxr-xr-xlibparc/parc/algol/parc_Memory.c144
-rw-r--r--libparc/parc/algol/parc_Memory.h468
-rw-r--r--libparc/parc/algol/parc_Network.c390
-rw-r--r--libparc/parc/algol/parc_Network.h299
-rw-r--r--libparc/parc/algol/parc_Object.c952
-rw-r--r--libparc/parc/algol/parc_Object.h1504
-rwxr-xr-xlibparc/parc/algol/parc_OldSortedList.c101
-rwxr-xr-xlibparc/parc/algol/parc_OldSortedList.h122
-rwxr-xr-xlibparc/parc/algol/parc_OutputStream.c81
-rwxr-xr-xlibparc/parc/algol/parc_OutputStream.h190
-rwxr-xr-xlibparc/parc/algol/parc_PathName.c277
-rw-r--r--libparc/parc/algol/parc_PathName.h392
-rwxr-xr-xlibparc/parc/algol/parc_PriorityQueue.c387
-rwxr-xr-xlibparc/parc/algol/parc_PriorityQueue.h223
-rw-r--r--libparc/parc/algol/parc_Properties.c342
-rw-r--r--libparc/parc/algol/parc_Properties.h502
-rwxr-xr-xlibparc/parc/algol/parc_RandomAccessFile.c185
-rwxr-xr-xlibparc/parc/algol/parc_RandomAccessFile.h426
-rwxr-xr-xlibparc/parc/algol/parc_ReadOnlyBuffer.c245
-rw-r--r--libparc/parc/algol/parc_ReadOnlyBuffer.h834
-rw-r--r--libparc/parc/algol/parc_SafeMemory.c658
-rw-r--r--libparc/parc/algol/parc_SafeMemory.h335
-rw-r--r--libparc/parc/algol/parc_SortedList.c252
-rw-r--r--libparc/parc/algol/parc_SortedList.h595
-rwxr-xr-xlibparc/parc/algol/parc_Stack.c76
-rwxr-xr-xlibparc/parc/algol/parc_Stack.h140
-rw-r--r--libparc/parc/algol/parc_StandardOutputStream.c76
-rw-r--r--libparc/parc/algol/parc_StandardOutputStream.h38
-rwxr-xr-xlibparc/parc/algol/parc_StdlibMemory.c180
-rwxr-xr-xlibparc/parc/algol/parc_StdlibMemory.h200
-rwxr-xr-xlibparc/parc/algol/parc_String.c187
-rw-r--r--libparc/parc/algol/parc_String.h391
-rwxr-xr-xlibparc/parc/algol/parc_Time.c154
-rw-r--r--libparc/parc/algol/parc_Time.h262
-rwxr-xr-xlibparc/parc/algol/parc_TreeMap.c1120
-rwxr-xr-xlibparc/parc/algol/parc_TreeMap.h714
-rwxr-xr-xlibparc/parc/algol/parc_TreeRedBlack.c781
-rwxr-xr-xlibparc/parc/algol/parc_TreeRedBlack.h384
-rw-r--r--libparc/parc/algol/parc_URI.c468
-rw-r--r--libparc/parc/algol/parc_URI.h412
-rw-r--r--libparc/parc/algol/parc_URIAuthority.c133
-rw-r--r--libparc/parc/algol/parc_URIAuthority.h237
-rwxr-xr-xlibparc/parc/algol/parc_URIPath.c309
-rwxr-xr-xlibparc/parc/algol/parc_URIPath.h494
-rwxr-xr-xlibparc/parc/algol/parc_URISegment.c276
-rw-r--r--libparc/parc/algol/parc_URISegment.h355
-rw-r--r--libparc/parc/algol/parc_Unsigned.c176
-rwxr-xr-xlibparc/parc/algol/parc_Unsigned.h91
-rwxr-xr-xlibparc/parc/algol/parc_Varint.c543
-rwxr-xr-xlibparc/parc/algol/parc_Varint.h478
-rwxr-xr-xlibparc/parc/algol/parc_Vector.c81
-rwxr-xr-xlibparc/parc/algol/parc_Vector.h109
-rw-r--r--libparc/parc/algol/test/.gitignore73
-rw-r--r--libparc/parc/algol/test/CMakeLists.txt76
-rw-r--r--libparc/parc/algol/test/_test_parc_URI.h57
-rw-r--r--libparc/parc/algol/test/data.json2614
-rwxr-xr-xlibparc/parc/algol/test/test_parc_ArrayList.c658
-rw-r--r--libparc/parc/algol/test/test_parc_AtomicInteger.c156
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Base64.c414
-rwxr-xr-xlibparc/parc/algol/test/test_parc_BitVector.c438
-rw-r--r--libparc/parc/algol/test/test_parc_Buffer.c1502
-rwxr-xr-xlibparc/parc/algol/test/test_parc_BufferChunker.c336
-rw-r--r--libparc/parc/algol/test/test_parc_BufferComposer.c448
-rwxr-xr-xlibparc/parc/algol/test/test_parc_ByteArray.c499
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Chunker.c271
-rw-r--r--libparc/parc/algol/test/test_parc_Clock.c198
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Deque.c620
-rw-r--r--libparc/parc/algol/test/test_parc_Dictionary.c736
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Display.c85
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Environment.c86
-rw-r--r--libparc/parc/algol/test/test_parc_Event.c243
-rw-r--r--libparc/parc/algol/test/test_parc_EventBuffer.c345
-rw-r--r--libparc/parc/algol/test/test_parc_EventQueue.c402
-rwxr-xr-xlibparc/parc/algol/test/test_parc_EventScheduler.c263
-rw-r--r--libparc/parc/algol/test/test_parc_EventSignal.c167
-rw-r--r--libparc/parc/algol/test/test_parc_EventSocket.c128
-rwxr-xr-xlibparc/parc/algol/test/test_parc_EventTimer.c143
-rw-r--r--libparc/parc/algol/test/test_parc_File.c208
-rwxr-xr-xlibparc/parc/algol/test/test_parc_FileChunker.c431
-rwxr-xr-xlibparc/parc/algol/test/test_parc_FileInputStream.c107
-rwxr-xr-xlibparc/parc/algol/test/test_parc_FileOutputStream.c167
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Hash.c253
-rwxr-xr-xlibparc/parc/algol/test/test_parc_HashCode.c109
-rwxr-xr-xlibparc/parc/algol/test/test_parc_HashCodeTable.c423
-rw-r--r--libparc/parc/algol/test/test_parc_HashMap.c915
-rwxr-xr-xlibparc/parc/algol/test/test_parc_InputStream.c109
-rw-r--r--libparc/parc/algol/test/test_parc_Iterator.c192
-rw-r--r--libparc/parc/algol/test/test_parc_JSON.c690
-rwxr-xr-xlibparc/parc/algol/test/test_parc_JSONArray.c227
-rw-r--r--libparc/parc/algol/test/test_parc_JSONPair.c421
-rwxr-xr-xlibparc/parc/algol/test/test_parc_JSONParser.c310
-rw-r--r--libparc/parc/algol/test/test_parc_JSONValue.c1365
-rwxr-xr-xlibparc/parc/algol/test/test_parc_KeyValue.c386
-rwxr-xr-xlibparc/parc/algol/test/test_parc_KeyedElement.c134
-rw-r--r--libparc/parc/algol/test/test_parc_LinkedList.c1192
-rw-r--r--libparc/parc/algol/test/test_parc_List.c872
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Memory.c220
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Network.c668
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Object.c1580
-rwxr-xr-xlibparc/parc/algol/test/test_parc_PathName.c458
-rw-r--r--libparc/parc/algol/test/test_parc_PriorityQueue.c492
-rw-r--r--libparc/parc/algol/test/test_parc_Properties.c277
-rw-r--r--libparc/parc/algol/test/test_parc_RandomAccessFile.c380
-rw-r--r--libparc/parc/algol/test/test_parc_ReadOnlyBuffer.c689
-rw-r--r--libparc/parc/algol/test/test_parc_SafeMemory.c813
-rw-r--r--libparc/parc/algol/test/test_parc_SortedList.c510
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Stack.c119
-rw-r--r--libparc/parc/algol/test/test_parc_StdlibMemory.c326
-rw-r--r--libparc/parc/algol/test/test_parc_String.c210
-rw-r--r--libparc/parc/algol/test/test_parc_Time.c144
-rwxr-xr-xlibparc/parc/algol/test/test_parc_TreeMap.c1565
-rwxr-xr-xlibparc/parc/algol/test/test_parc_TreeRedBlack.c1461
-rw-r--r--libparc/parc/algol/test/test_parc_URI.c642
-rw-r--r--libparc/parc/algol/test/test_parc_URIAuthority.c267
-rw-r--r--libparc/parc/algol/test/test_parc_URIPath.c406
-rw-r--r--libparc/parc/algol/test/test_parc_URISegment.c315
-rwxr-xr-xlibparc/parc/algol/test/test_parc_Varint.c310
-rw-r--r--libparc/parc/algol/test/test_parc_Vector.c116
-rw-r--r--libparc/parc/concurrent/.gitignore5
-rwxr-xr-xlibparc/parc/concurrent/parc_AtomicUint16.c178
-rwxr-xr-xlibparc/parc/concurrent/parc_AtomicUint16.h341
-rwxr-xr-xlibparc/parc/concurrent/parc_AtomicUint32.c178
-rwxr-xr-xlibparc/parc/concurrent/parc_AtomicUint32.h341
-rwxr-xr-xlibparc/parc/concurrent/parc_AtomicUint64.c178
-rwxr-xr-xlibparc/parc/concurrent/parc_AtomicUint64.h341
-rwxr-xr-xlibparc/parc/concurrent/parc_AtomicUint8.c178
-rwxr-xr-xlibparc/parc/concurrent/parc_AtomicUint8.h341
-rwxr-xr-xlibparc/parc/concurrent/parc_FutureTask.c304
-rwxr-xr-xlibparc/parc/concurrent/parc_FutureTask.h657
-rwxr-xr-xlibparc/parc/concurrent/parc_Lock.c202
-rwxr-xr-xlibparc/parc/concurrent/parc_Lock.h377
-rwxr-xr-xlibparc/parc/concurrent/parc_Notifier.c149
-rwxr-xr-xlibparc/parc/concurrent/parc_Notifier.h178
-rwxr-xr-xlibparc/parc/concurrent/parc_RingBuffer.c75
-rwxr-xr-xlibparc/parc/concurrent/parc_RingBuffer.h162
-rwxr-xr-xlibparc/parc/concurrent/parc_RingBuffer_1x1.c235
-rwxr-xr-xlibparc/parc/concurrent/parc_RingBuffer_1x1.h143
-rwxr-xr-xlibparc/parc/concurrent/parc_RingBuffer_NxM.c167
-rwxr-xr-xlibparc/parc/concurrent/parc_RingBuffer_NxM.h146
-rwxr-xr-xlibparc/parc/concurrent/parc_ScheduledTask.c203
-rwxr-xr-xlibparc/parc/concurrent/parc_ScheduledTask.h467
-rw-r--r--libparc/parc/concurrent/parc_ScheduledThreadPool.c323
-rwxr-xr-xlibparc/parc/concurrent/parc_ScheduledThreadPool.h429
-rwxr-xr-xlibparc/parc/concurrent/parc_Synchronizer.c146
-rwxr-xr-xlibparc/parc/concurrent/parc_Synchronizer.h277
-rw-r--r--libparc/parc/concurrent/parc_Thread.c232
-rwxr-xr-xlibparc/parc/concurrent/parc_Thread.h601
-rw-r--r--libparc/parc/concurrent/parc_ThreadPool.c457
-rwxr-xr-xlibparc/parc/concurrent/parc_ThreadPool.h625
-rwxr-xr-xlibparc/parc/concurrent/parc_Timeout.c25
-rw-r--r--libparc/parc/concurrent/parc_Timeout.h141
-rwxr-xr-xlibparc/parc/concurrent/parc_Timer.c173
-rwxr-xr-xlibparc/parc/concurrent/parc_Timer.h431
-rw-r--r--libparc/parc/concurrent/test/.gitignore10
-rw-r--r--libparc/parc/concurrent/test/CMakeLists.txt25
-rw-r--r--libparc/parc/concurrent/test/test_parc_AtomicUint16.c361
-rw-r--r--libparc/parc/concurrent/test/test_parc_AtomicUint32.c361
-rw-r--r--libparc/parc/concurrent/test/test_parc_AtomicUint64.c361
-rw-r--r--libparc/parc/concurrent/test/test_parc_AtomicUint8.c361
-rw-r--r--libparc/parc/concurrent/test/test_parc_FutureTask.c317
-rw-r--r--libparc/parc/concurrent/test/test_parc_Lock.c352
-rwxr-xr-xlibparc/parc/concurrent/test/test_parc_Notifier.c267
-rwxr-xr-xlibparc/parc/concurrent/test/test_parc_RingBuffer_1x1.c325
-rwxr-xr-xlibparc/parc/concurrent/test/test_parc_RingBuffer_NxM.c106
-rw-r--r--libparc/parc/concurrent/test/test_parc_ScheduledTask.c244
-rw-r--r--libparc/parc/concurrent/test/test_parc_ScheduledThreadPool.c301
-rwxr-xr-xlibparc/parc/concurrent/test/test_parc_Synchronizer.c179
-rw-r--r--libparc/parc/concurrent/test/test_parc_Thread.c264
-rw-r--r--libparc/parc/concurrent/test/test_parc_ThreadPool.c273
-rw-r--r--libparc/parc/concurrent/test/test_parc_Timer.c213
-rw-r--r--libparc/parc/config.h.in6
-rw-r--r--libparc/parc/developer/parc_Stopwatch.c266
-rw-r--r--libparc/parc/developer/parc_Stopwatch.h446
-rwxr-xr-xlibparc/parc/developer/parc_Timing.h238
-rwxr-xr-xlibparc/parc/developer/parc_TimingDarwin.h66
-rwxr-xr-xlibparc/parc/developer/parc_TimingGeneric.h56
-rwxr-xr-xlibparc/parc/developer/parc_TimingIntel.c89
-rwxr-xr-xlibparc/parc/developer/parc_TimingIntel.h102
-rwxr-xr-xlibparc/parc/developer/parc_TimingLinux.h62
-rw-r--r--libparc/parc/developer/test/.gitignore2
-rw-r--r--libparc/parc/developer/test/CMakeLists.txt14
-rw-r--r--libparc/parc/developer/test/test_parc_Stopwatch.c251
-rwxr-xr-xlibparc/parc/developer/test/test_parc_Timing.c127
-rw-r--r--libparc/parc/libparc_About.c44
-rwxr-xr-xlibparc/parc/libparc_About.h54
-rwxr-xr-xlibparc/parc/logging/parc_Log.c241
-rw-r--r--libparc/parc/logging/parc_Log.h418
-rw-r--r--libparc/parc/logging/parc_LogEntry.c162
-rwxr-xr-xlibparc/parc/logging/parc_LogEntry.h274
-rwxr-xr-xlibparc/parc/logging/parc_LogFormatSyslog.c122
-rwxr-xr-xlibparc/parc/logging/parc_LogFormatSyslog.h31
-rwxr-xr-xlibparc/parc/logging/parc_LogFormatText.c51
-rwxr-xr-xlibparc/parc/logging/parc_LogFormatText.h31
-rwxr-xr-xlibparc/parc/logging/parc_LogLevel.c92
-rwxr-xr-xlibparc/parc/logging/parc_LogLevel.h132
-rwxr-xr-xlibparc/parc/logging/parc_LogManager.c55
-rwxr-xr-xlibparc/parc/logging/parc_LogManager.h91
-rwxr-xr-xlibparc/parc/logging/parc_LogReporter.c71
-rwxr-xr-xlibparc/parc/logging/parc_LogReporter.h145
-rwxr-xr-xlibparc/parc/logging/parc_LogReporterFile.c62
-rwxr-xr-xlibparc/parc/logging/parc_LogReporterFile.h112
-rwxr-xr-xlibparc/parc/logging/parc_LogReporterTextStdout.c66
-rwxr-xr-xlibparc/parc/logging/parc_LogReporterTextStdout.h102
-rw-r--r--libparc/parc/logging/test/.gitignore12
-rw-r--r--libparc/parc/logging/test/CMakeLists.txt20
-rw-r--r--libparc/parc/logging/test/test_parc_Log.c345
-rw-r--r--libparc/parc/logging/test/test_parc_LogEntry.c465
-rwxr-xr-xlibparc/parc/logging/test/test_parc_LogFormatSyslog.c97
-rw-r--r--libparc/parc/logging/test/test_parc_LogFormatText.c95
-rwxr-xr-xlibparc/parc/logging/test/test_parc_LogLevel.c138
-rw-r--r--libparc/parc/logging/test/test_parc_LogReporter.c164
-rwxr-xr-xlibparc/parc/logging/test/test_parc_LogReporterFile.c149
-rwxr-xr-xlibparc/parc/logging/test/test_parc_LogReporterTextStdout.c128
-rw-r--r--libparc/parc/memory/parc_BufferPool.c236
-rw-r--r--libparc/parc/memory/parc_BufferPool.h344
-rw-r--r--libparc/parc/memory/test/CMakeLists.txt13
-rw-r--r--libparc/parc/memory/test/test_parc_BufferPool.c370
-rw-r--r--libparc/parc/object/test/CMakeLists.txt12
-rw-r--r--libparc/parc/security/.gitignore5
-rw-r--r--libparc/parc/security/command-line/.gitignore1
-rw-r--r--libparc/parc/security/command-line/CMakeLists.txt8
-rw-r--r--libparc/parc/security/command-line/parc-publickey.c128
-rw-r--r--libparc/parc/security/command-line/parcPublicKey_About.c44
-rwxr-xr-xlibparc/parc/security/command-line/parcPublicKey_About.h54
-rwxr-xr-xlibparc/parc/security/parc_Certificate.c135
-rwxr-xr-xlibparc/parc/security/parc_Certificate.h352
-rw-r--r--libparc/parc/security/parc_CertificateFactory.c107
-rwxr-xr-xlibparc/parc/security/parc_CertificateFactory.h166
-rwxr-xr-xlibparc/parc/security/parc_CertificateType.c55
-rwxr-xr-xlibparc/parc/security/parc_CertificateType.h65
-rwxr-xr-xlibparc/parc/security/parc_ContainerEncoding.c57
-rwxr-xr-xlibparc/parc/security/parc_ContainerEncoding.h67
-rwxr-xr-xlibparc/parc/security/parc_CryptoCache.c157
-rwxr-xr-xlibparc/parc/security/parc_CryptoCache.h94
-rwxr-xr-xlibparc/parc/security/parc_CryptoHash.c134
-rwxr-xr-xlibparc/parc/security/parc_CryptoHash.h234
-rw-r--r--libparc/parc/security/parc_CryptoHashType.c57
-rwxr-xr-xlibparc/parc/security/parc_CryptoHashType.h71
-rwxr-xr-xlibparc/parc/security/parc_CryptoHasher.c530
-rwxr-xr-xlibparc/parc/security/parc_CryptoHasher.h306
-rwxr-xr-xlibparc/parc/security/parc_CryptoSuite.c111
-rwxr-xr-xlibparc/parc/security/parc_CryptoSuite.h118
-rw-r--r--libparc/parc/security/parc_DiffieHellman.c55
-rw-r--r--libparc/parc/security/parc_DiffieHellman.h119
-rwxr-xr-xlibparc/parc/security/parc_DiffieHellmanGroup.h31
-rw-r--r--libparc/parc/security/parc_DiffieHellmanKeyShare.c297
-rw-r--r--libparc/parc/security/parc_DiffieHellmanKeyShare.h151
-rwxr-xr-xlibparc/parc/security/parc_Identity.c116
-rwxr-xr-xlibparc/parc/security/parc_Identity.h343
-rw-r--r--libparc/parc/security/parc_IdentityFile.c149
-rw-r--r--libparc/parc/security/parc_IdentityFile.h271
-rw-r--r--libparc/parc/security/parc_InMemoryVerifier.c395
-rwxr-xr-xlibparc/parc/security/parc_InMemoryVerifier.h90
-rwxr-xr-xlibparc/parc/security/parc_Key.c206
-rwxr-xr-xlibparc/parc/security/parc_Key.h325
-rwxr-xr-xlibparc/parc/security/parc_KeyId.c141
-rwxr-xr-xlibparc/parc/security/parc_KeyId.h348
-rwxr-xr-xlibparc/parc/security/parc_KeyStore.c113
-rwxr-xr-xlibparc/parc/security/parc_KeyStore.h378
-rw-r--r--libparc/parc/security/parc_KeyType.c56
-rw-r--r--libparc/parc/security/parc_KeyType.h66
-rw-r--r--libparc/parc/security/parc_Pkcs12KeyStore.c454
-rw-r--r--libparc/parc/security/parc_Pkcs12KeyStore.h134
-rw-r--r--libparc/parc/security/parc_PublicKeySigner.c323
-rw-r--r--libparc/parc/security/parc_PublicKeySigner.h342
-rw-r--r--libparc/parc/security/parc_SecureRandom.c123
-rw-r--r--libparc/parc/security/parc_SecureRandom.h189
-rw-r--r--libparc/parc/security/parc_Security.c210
-rwxr-xr-xlibparc/parc/security/parc_Security.h89
-rwxr-xr-xlibparc/parc/security/parc_Signature.c123
-rwxr-xr-xlibparc/parc/security/parc_Signature.h250
-rw-r--r--libparc/parc/security/parc_Signer.c178
-rwxr-xr-xlibparc/parc/security/parc_Signer.h414
-rwxr-xr-xlibparc/parc/security/parc_SigningAlgorithm.c59
-rw-r--r--libparc/parc/security/parc_SigningAlgorithm.h77
-rw-r--r--libparc/parc/security/parc_SymmetricKeySigner.c281
-rw-r--r--libparc/parc/security/parc_SymmetricKeySigner.h355
-rw-r--r--libparc/parc/security/parc_SymmetricKeyStore.c477
-rw-r--r--libparc/parc/security/parc_SymmetricKeyStore.h169
-rwxr-xr-xlibparc/parc/security/parc_Verifier.c107
-rw-r--r--libparc/parc/security/parc_Verifier.h272
-rw-r--r--libparc/parc/security/parc_X509Certificate.c645
-rwxr-xr-xlibparc/parc/security/parc_X509Certificate.h208
-rw-r--r--libparc/parc/security/test/.gitignore24
-rw-r--r--libparc/parc/security/test/CMakeLists.txt88
-rw-r--r--libparc/parc/security/test/README.digests12
-rw-r--r--libparc/parc/security/test/README.keystore63
-rw-r--r--libparc/parc/security/test/README.symmetric9
-rw-r--r--libparc/parc/security/test/test.crt.derbin0 -> 559 bytes
-rw-r--r--libparc/parc/security/test/test.crt.der.sha256.bin1
-rw-r--r--libparc/parc/security/test/test.derbin0 -> 162 bytes
-rw-r--r--libparc/parc/security/test/test.pem13
-rw-r--r--libparc/parc/security/test/test.pkcs12bin0 -> 1646 bytes
-rw-r--r--libparc/parc/security/test/test_crt.derbin0 -> 517 bytes
-rw-r--r--libparc/parc/security/test/test_crt_der.binbin0 -> 517 bytes
-rw-r--r--libparc/parc/security/test/test_crt_sha256.bin1
-rw-r--r--libparc/parc/security/test/test_der.binbin0 -> 162 bytes
-rw-r--r--libparc/parc/security/test/test_digest_bytes_128.bin1
-rw-r--r--libparc/parc/security/test/test_digest_bytes_128.sha2561
-rw-r--r--libparc/parc/security/test/test_digest_bytes_128.sha5121
-rw-r--r--libparc/parc/security/test/test_ec.crt12
-rw-r--r--libparc/parc/security/test/test_ec.csr8
-rw-r--r--libparc/parc/security/test/test_ec.p12bin0 -> 1011 bytes
-rw-r--r--libparc/parc/security/test/test_ec_crt.derbin0 -> 438 bytes
-rw-r--r--libparc/parc/security/test/test_ec_crt_sha256.bin1
-rw-r--r--libparc/parc/security/test/test_ec_key.derbin0 -> 118 bytes
-rw-r--r--libparc/parc/security/test/test_ec_key.pem5
-rw-r--r--libparc/parc/security/test/test_ec_pub.derbin0 -> 88 bytes
-rw-r--r--libparc/parc/security/test/test_ec_pub.pem4
-rw-r--r--libparc/parc/security/test/test_ec_pub_sha256.bin1
-rw-r--r--libparc/parc/security/test/test_ec_pub_sha256.bin.sigbin0 -> 70 bytes
-rw-r--r--libparc/parc/security/test/test_key.pem6
-rw-r--r--libparc/parc/security/test/test_parc_Certificate.c258
-rwxr-xr-xlibparc/parc/security/test/test_parc_CertificateFactory.c160
-rwxr-xr-xlibparc/parc/security/test/test_parc_CertificateType.c90
-rwxr-xr-xlibparc/parc/security/test/test_parc_ContainerEncoding.c90
-rwxr-xr-xlibparc/parc/security/test/test_parc_CryptoCache.c228
-rwxr-xr-xlibparc/parc/security/test/test_parc_CryptoHash.c184
-rw-r--r--libparc/parc/security/test/test_parc_CryptoHashType.c92
-rwxr-xr-xlibparc/parc/security/test/test_parc_CryptoHasher.c407
-rwxr-xr-xlibparc/parc/security/test/test_parc_CryptoSuite.c82
-rwxr-xr-xlibparc/parc/security/test/test_parc_DiffieHellman.c93
-rwxr-xr-xlibparc/parc/security/test/test_parc_DiffieHellmanKeyShare.c229
-rw-r--r--libparc/parc/security/test/test_parc_Identity.c232
-rw-r--r--libparc/parc/security/test/test_parc_IdentityFile.c242
-rwxr-xr-xlibparc/parc/security/test/test_parc_InMemoryVerifier.c417
-rw-r--r--libparc/parc/security/test/test_parc_InMemoryVerifierECDSA.c417
-rwxr-xr-xlibparc/parc/security/test/test_parc_Key.c357
-rw-r--r--libparc/parc/security/test/test_parc_KeyId.c216
-rwxr-xr-xlibparc/parc/security/test/test_parc_KeyStore.c137
-rwxr-xr-xlibparc/parc/security/test/test_parc_Pkcs12KeyStore.c470
-rw-r--r--libparc/parc/security/test/test_parc_Pkcs12KeyStoreECDSA.c470
-rw-r--r--libparc/parc/security/test/test_parc_PublicKeyECSigner.c507
-rw-r--r--libparc/parc/security/test/test_parc_PublicKeySigner.c466
-rwxr-xr-xlibparc/parc/security/test/test_parc_SecureRandom.c241
-rwxr-xr-xlibparc/parc/security/test/test_parc_Security.c109
-rwxr-xr-xlibparc/parc/security/test/test_parc_Signature.c230
-rw-r--r--libparc/parc/security/test/test_parc_Signer.c305
-rw-r--r--libparc/parc/security/test/test_parc_SignerEC.c312
-rwxr-xr-xlibparc/parc/security/test/test_parc_SigningAlgorithm.c126
-rw-r--r--libparc/parc/security/test/test_parc_SymmetricKeySigner.c261
-rwxr-xr-xlibparc/parc/security/test/test_parc_SymmetricKeyStore.c351
-rwxr-xr-xlibparc/parc/security/test/test_parc_Verifier.c121
-rwxr-xr-xlibparc/parc/security/test/test_parc_X509Certificate.c244
-rw-r--r--libparc/parc/security/test/test_pubkey.bin1
-rw-r--r--libparc/parc/security/test/test_pubkey.der6
-rw-r--r--libparc/parc/security/test/test_pubkey.pem6
-rw-r--r--libparc/parc/security/test/test_random_bytesbin0 -> 512 bytes
-rw-r--r--libparc/parc/security/test/test_random_bytes.hmac_sha256bin0 -> 32 bytes
-rw-r--r--libparc/parc/security/test/test_random_bytes.hmac_sha512bin0 -> 64 bytes
-rw-r--r--libparc/parc/security/test/test_random_bytes.sigbin0 -> 128 bytes
-rw-r--r--libparc/parc/security/test/test_random_bytes.sig_ecbin0 -> 71 bytes
-rw-r--r--libparc/parc/security/test/test_rsa.crt13
-rw-r--r--libparc/parc/security/test/test_rsa.csr11
-rw-r--r--libparc/parc/security/test/test_rsa.p12bin0 -> 1598 bytes
-rw-r--r--libparc/parc/security/test/test_rsa_crt.derbin0 -> 517 bytes
-rw-r--r--libparc/parc/security/test/test_rsa_crt_sha256.bin2
-rw-r--r--libparc/parc/security/test/test_rsa_key.derbin0 -> 608 bytes
-rw-r--r--libparc/parc/security/test/test_rsa_key.pem15
-rw-r--r--libparc/parc/security/test/test_rsa_pub.derbin0 -> 162 bytes
-rw-r--r--libparc/parc/security/test/test_rsa_pub.pem6
-rw-r--r--libparc/parc/security/test/test_rsa_pub_sha256.bin1
-rw-r--r--libparc/parc/security/test/test_symmetric_key.binbin0 -> 32 bytes
-rw-r--r--libparc/parc/security/test/test_symmetric_key.sha2561
-rw-r--r--libparc/parc/statistics/parc_BasicStats.c259
-rwxr-xr-xlibparc/parc/statistics/parc_BasicStats.h466
-rw-r--r--libparc/parc/statistics/parc_EWMA.c207
-rwxr-xr-xlibparc/parc/statistics/parc_EWMA.h413
-rw-r--r--libparc/parc/statistics/test/CMakeLists.txt14
-rw-r--r--libparc/parc/statistics/test/test_parc_BasicStats.c246
-rw-r--r--libparc/parc/statistics/test/test_parc_EWMA.c257
-rwxr-xr-xlibparc/parc/testing/parc_MemoryTesting.c44
-rwxr-xr-xlibparc/parc/testing/parc_MemoryTesting.h47
-rw-r--r--libparc/parc/testing/parc_ObjectTesting.c266
-rw-r--r--libparc/parc/testing/parc_ObjectTesting.h253
-rw-r--r--libparc/parc/testing/test/.gitignore2
-rw-r--r--libparc/parc/testing/test/CMakeLists.txt12
-rwxr-xr-xlibparc/parc/testing/test/test_parc_MemoryTesting.c86
-rwxr-xr-xlibparc/parc/testing/test/test_parc_ObjectTesting.c543
-rw-r--r--libparc/scripts/build-package.sh198
-rw-r--r--libparc/scripts/version57
-rw-r--r--longbow/.gitignore30
-rw-r--r--longbow/AUTHORS7
-rw-r--r--longbow/BASE_VERSION1
-rw-r--r--longbow/CMakeLists.txt174
-rw-r--r--longbow/LICENSE12
-rw-r--r--longbow/README.md113
-rw-r--r--longbow/cmake/Modules/FindUncrustify.cmake8
-rwxr-xr-xlongbow/cmake/get_version.sh20
-rw-r--r--longbow/documentation/.gitignore4
-rw-r--r--longbow/documentation/CMakeLists.txt45
-rw-r--r--longbow/documentation/DoxygenLayout.xml196
-rw-r--r--longbow/documentation/LaTeX Documentation/.gitignore7
-rw-r--r--longbow/documentation/LaTeX Documentation/Abstract.tex7
-rw-r--r--longbow/documentation/LaTeX Documentation/Document.tex730
-rw-r--r--longbow/documentation/LaTeX Documentation/LongBow.tex37
-rw-r--r--longbow/documentation/LaTeX Documentation/PARCOneColumn.cls288
-rw-r--r--longbow/documentation/LaTeX Documentation/Packages.tex58
-rw-r--r--longbow/documentation/LaTeX Documentation/Title.tex13
-rw-r--r--longbow/documentation/LaTeX Documentation/old/Longbow_documentation.tex769
-rwxr-xr-xlongbow/documentation/LaTeX Documentation/old/SelfArx2.cls191
-rw-r--r--longbow/documentation/LaTeX Documentation/parc_black_solid.pngbin0 -> 24543 bytes
-rw-r--r--longbow/documentation/LongBow.pages/Index.zipbin0 -> 44685 bytes
-rw-r--r--longbow/documentation/LongBow.pages/Metadata/BuildVersionHistory.plist14
-rw-r--r--longbow/documentation/LongBow.pages/Metadata/DocumentIdentifier1
-rw-r--r--longbow/documentation/LongBow.pages/Metadata/Properties.plistbin0 -> 217 bytes
-rw-r--r--longbow/documentation/LongBow.pages/preview-micro.jpgbin0 -> 1575 bytes
-rw-r--r--longbow/documentation/LongBow.pages/preview-web.jpgbin0 -> 13506 bytes
-rw-r--r--longbow/documentation/LongBow.pages/preview.jpgbin0 -> 194777 bytes
-rw-r--r--longbow/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css470
-rw-r--r--longbow/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css.map1
-rw-r--r--longbow/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.min.css5
-rw-r--r--longbow/documentation/doxygen-extras/bootstrap/css/bootstrap.css6332
-rw-r--r--longbow/documentation/doxygen-extras/bootstrap/css/bootstrap.css.map1
-rw-r--r--longbow/documentation/doxygen-extras/bootstrap/css/bootstrap.min.css5
-rw-r--r--longbow/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.eotbin0 -> 20335 bytes
-rw-r--r--longbow/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.svg229
-rw-r--r--longbow/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.ttfbin0 -> 41280 bytes
-rw-r--r--longbow/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.woffbin0 -> 23320 bytes
-rw-r--r--longbow/documentation/doxygen-extras/bootstrap/js/bootstrap.js2320
-rw-r--r--longbow/documentation/doxygen-extras/bootstrap/js/bootstrap.min.js7
-rw-r--r--longbow/documentation/doxygen-extras/bootstrap/js/npm.js13
-rw-r--r--longbow/documentation/doxygen-extras/customdoxygen.css1705
-rw-r--r--longbow/documentation/doxygen-extras/doxy-boot.js120
-rwxr-xr-xlongbow/documentation/doxygen-extras/doxygen-bootstrap.js119
-rwxr-xr-xlongbow/documentation/doxygen-extras/footer.html31
-rwxr-xr-xlongbow/documentation/doxygen-extras/header.html47
-rw-r--r--longbow/documentation/doxygen-extras/masthead.css9
-rwxr-xr-xlongbow/documentation/examples/testAssertion.c22
-rw-r--r--longbow/documentation/images/logo_fdio.pngbin0 -> 3092 bytes
-rw-r--r--longbow/documentation/images/noise_gradient.jpgbin0 -> 6823 bytes
-rw-r--r--longbow/documentation/imported-stylesheet.css1
-rw-r--r--longbow/documentation/longbow-logo.gifbin0 -> 3565 bytes
-rw-r--r--longbow/documentation/longbow.conf2382
-rw-r--r--longbow/documentation/longbow.doxygen.in2385
-rw-r--r--longbow/documentation/longbow.gifbin0 -> 28852 bytes
-rw-r--r--longbow/documentation/stylesheet.css47
-rw-r--r--longbow/scripts/build-package.sh196
-rw-r--r--longbow/scripts/version57
-rw-r--r--longbow/src/CMakeLists.txt2
-rw-r--r--longbow/src/LongBow/.gitignore2
-rw-r--r--longbow/src/LongBow/CMakeLists.txt191
-rw-r--r--longbow/src/LongBow/Groups.dox47
-rw-r--r--longbow/src/LongBow/Reporting/ANSITerm/longBowReportANSITerminal_About.c44
-rwxr-xr-xlongbow/src/LongBow/Reporting/ANSITerm/longBowReportANSITerminal_About.h54
-rw-r--r--longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Runtime.c291
-rwxr-xr-xlongbow/src/LongBow/Reporting/ANSITerm/longBowReport_Runtime.h67
-rw-r--r--longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Testing.c191
-rw-r--r--longbow/src/LongBow/Reporting/Android/longBowReportAndroid_About.c44
-rwxr-xr-xlongbow/src/LongBow/Reporting/Android/longBowReportAndroid_About.h54
-rw-r--r--longbow/src/LongBow/Reporting/Android/longBowReport_Runtime.c92
-rwxr-xr-xlongbow/src/LongBow/Reporting/Android/longBowReport_Testing.c198
-rw-r--r--longbow/src/LongBow/Reporting/TextPlain/longBowReportTextPlain_About.c44
-rwxr-xr-xlongbow/src/LongBow/Reporting/TextPlain/longBowReportTextPlain_About.h54
-rwxr-xr-xlongbow/src/LongBow/Reporting/TextPlain/longBowReport_Runtime.c95
-rwxr-xr-xlongbow/src/LongBow/Reporting/TextPlain/longBowReport_Testing.c193
-rwxr-xr-xlongbow/src/LongBow/Reporting/longBowReport_Runtime.c50
-rwxr-xr-xlongbow/src/LongBow/Reporting/longBowReport_Runtime.h146
-rwxr-xr-xlongbow/src/LongBow/Reporting/longBowReport_Testing.c22
-rwxr-xr-xlongbow/src/LongBow/Reporting/longBowReport_Testing.h71
-rw-r--r--longbow/src/LongBow/assertions.h152
-rw-r--r--longbow/src/LongBow/command-line/.gitignore2
-rwxr-xr-xlongbow/src/LongBow/command-line/liblongbow-config.c58
-rw-r--r--longbow/src/LongBow/config.h.in11
-rwxr-xr-xlongbow/src/LongBow/debugging.h51
-rw-r--r--longbow/src/LongBow/longBow_About.c44
-rwxr-xr-xlongbow/src/LongBow/longBow_About.h54
-rwxr-xr-xlongbow/src/LongBow/longBow_Backtrace.c136
-rwxr-xr-xlongbow/src/LongBow/longBow_Backtrace.h80
-rw-r--r--longbow/src/LongBow/longBow_ClipBoard.c155
-rwxr-xr-xlongbow/src/LongBow/longBow_ClipBoard.h52
-rwxr-xr-xlongbow/src/LongBow/longBow_Compiler.h302
-rwxr-xr-xlongbow/src/LongBow/longBow_Config.c252
-rwxr-xr-xlongbow/src/LongBow/longBow_Config.h126
-rwxr-xr-xlongbow/src/LongBow/longBow_Debug.c140
-rwxr-xr-xlongbow/src/LongBow/longBow_Debug.h98
-rwxr-xr-xlongbow/src/LongBow/longBow_Event.c122
-rwxr-xr-xlongbow/src/LongBow/longBow_Event.h152
-rwxr-xr-xlongbow/src/LongBow/longBow_EventType.c224
-rwxr-xr-xlongbow/src/LongBow/longBow_EventType.h409
-rwxr-xr-xlongbow/src/LongBow/longBow_Location.c88
-rwxr-xr-xlongbow/src/LongBow/longBow_Location.h88
-rwxr-xr-xlongbow/src/LongBow/longBow_Main.c59
-rwxr-xr-xlongbow/src/LongBow/longBow_Main.h52
-rwxr-xr-xlongbow/src/LongBow/longBow_MeasureTime.c96
-rw-r--r--longbow/src/LongBow/longBow_MeasureTime.h95
-rw-r--r--longbow/src/LongBow/longBow_Properties.c153
-rwxr-xr-xlongbow/src/LongBow/longBow_Properties.h46
-rwxr-xr-xlongbow/src/LongBow/longBow_Runtime.c268
-rw-r--r--longbow/src/LongBow/longBow_Runtime.h206
-rwxr-xr-xlongbow/src/LongBow/longBow_RuntimeResult.c75
-rwxr-xr-xlongbow/src/LongBow/longBow_RuntimeResult.h138
-rw-r--r--longbow/src/LongBow/longBow_Status.c146
-rwxr-xr-xlongbow/src/LongBow/longBow_Status.h235
-rwxr-xr-xlongbow/src/LongBow/longBow_SubProcess.c20
-rwxr-xr-xlongbow/src/LongBow/longBow_SubProcess.h145
-rwxr-xr-xlongbow/src/LongBow/longBow_SubProcess_Darwin_x86_64.c136
-rw-r--r--longbow/src/LongBow/longBow_TestCase.c643
-rwxr-xr-xlongbow/src/LongBow/longBow_TestCase.h247
-rwxr-xr-xlongbow/src/LongBow/longBow_TestCaseClipBoard.c58
-rwxr-xr-xlongbow/src/LongBow/longBow_TestCaseClipBoard.h62
-rwxr-xr-xlongbow/src/LongBow/longBow_TestCaseMetaData.c18
-rwxr-xr-xlongbow/src/LongBow/longBow_TestCaseMetaData.h34
-rw-r--r--longbow/src/LongBow/longBow_TestFixture.c449
-rw-r--r--longbow/src/LongBow/longBow_TestFixture.h274
-rwxr-xr-xlongbow/src/LongBow/longBow_TestFixtureConfig.c41
-rwxr-xr-xlongbow/src/LongBow/longBow_TestFixtureConfig.h68
-rw-r--r--longbow/src/LongBow/longBow_TestRunner.c256
-rw-r--r--longbow/src/LongBow/longBow_TestRunner.h269
-rwxr-xr-xlongbow/src/LongBow/longBow_UnitTest.h103
-rwxr-xr-xlongbow/src/LongBow/longBow_UnitTesting.c121
-rwxr-xr-xlongbow/src/LongBow/longBow_UnitTesting.h91
-rwxr-xr-xlongbow/src/LongBow/private/longBow_ArrayList.c277
-rw-r--r--longbow/src/LongBow/private/longBow_ArrayList.h225
-rw-r--r--longbow/src/LongBow/private/longBow_Memory.c95
-rwxr-xr-xlongbow/src/LongBow/private/longBow_Memory.h93
-rw-r--r--longbow/src/LongBow/private/longBow_OpenFile.c151
-rwxr-xr-xlongbow/src/LongBow/private/longBow_OpenFile.h70
-rw-r--r--longbow/src/LongBow/private/longBow_String.c180
-rwxr-xr-xlongbow/src/LongBow/private/longBow_String.h151
-rw-r--r--longbow/src/LongBow/runtime.h110
-rwxr-xr-xlongbow/src/LongBow/stubs/execinfo.h23
-rw-r--r--longbow/src/LongBow/test/.gitignore30
-rw-r--r--longbow/src/LongBow/test/CMakeLists.txt52
-rwxr-xr-xlongbow/src/LongBow/test/test_MemoryLeaks.c76
-rwxr-xr-xlongbow/src/LongBow/test/test_assertions.c23
-rwxr-xr-xlongbow/src/LongBow/test/test_fixtureConfiguration.c70
-rw-r--r--longbow/src/LongBow/test/test_longBow_ArrayList.c110
-rwxr-xr-xlongbow/src/LongBow/test/test_longBow_Backtrace.c106
-rwxr-xr-xlongbow/src/LongBow/test/test_longBow_CommandLineOptions.c73
-rwxr-xr-xlongbow/src/LongBow/test/test_longBow_Config.c98
-rwxr-xr-xlongbow/src/LongBow/test/test_longBow_Debug.c77
-rwxr-xr-xlongbow/src/LongBow/test/test_longBow_Expected.c71
-rw-r--r--longbow/src/LongBow/test/test_longBow_Fixture.c141
-rwxr-xr-xlongbow/src/LongBow/test/test_longBow_Location.c74
-rwxr-xr-xlongbow/src/LongBow/test/test_longBow_Main.c70
-rw-r--r--longbow/src/LongBow/test/test_longBow_MeasureTime.c155
-rwxr-xr-xlongbow/src/LongBow/test/test_longBow_Memory.c113
-rwxr-xr-xlongbow/src/LongBow/test/test_longBow_OpenFile.c85
-rwxr-xr-xlongbow/src/LongBow/test/test_longBow_Properties.c137
-rwxr-xr-xlongbow/src/LongBow/test/test_longBow_Runner.c74
-rwxr-xr-xlongbow/src/LongBow/test/test_longBow_Runtime.c80
-rwxr-xr-xlongbow/src/LongBow/test/test_longBow_Status.c140
-rwxr-xr-xlongbow/src/LongBow/test/test_longBow_String.c192
-rwxr-xr-xlongbow/src/LongBow/test/test_longBow_TestCase.c79
-rwxr-xr-xlongbow/src/LongBow/test/test_longBow_TestCaseClipBoard.c124
-rwxr-xr-xlongbow/src/LongBow/test/test_longBow_UnitTesting.c115
-rwxr-xr-xlongbow/src/LongBow/testing.h29
-rw-r--r--longbow/src/LongBow/tests.h47
-rwxr-xr-xlongbow/src/LongBow/traps.h164
-rw-r--r--longbow/src/LongBow/unit-test.h413
-rw-r--r--longbow/src/examples/.gitignore5
-rwxr-xr-xlongbow/src/examples/example1.c42
-rwxr-xr-xlongbow/src/examples/minimal.c25
-rwxr-xr-xlongbow/src/examples/pointer.c32
-rwxr-xr-xlongbow/src/examples/require.c41
-rwxr-xr-xlongbow/src/examples/testAssertion.c22
-rwxr-xr-xlongbow/src/examples/testClipboard.c71
-rwxr-xr-xlongbow/src/examples/testExample1.c97
-rwxr-xr-xlongbow/src/examples/testLongBow.c152
-rwxr-xr-xlongbow/src/examples/testRunnerSkipped.c68
-rwxr-xr-xlongbow/src/examples/testTearDown.c90
-rwxr-xr-xlongbow/src/examples/testUnimplemented.c61
-rwxr-xr-xlongbow/src/examples/test_minimal.c63
-rw-r--r--longbow/src/examples/tutorial/.gitignore3
-rw-r--r--longbow/src/examples/tutorial/test_tutorial1.c18
-rw-r--r--longbow/src/examples/tutorial/test_tutorial10.c68
-rw-r--r--longbow/src/examples/tutorial/test_tutorial11.c76
-rw-r--r--longbow/src/examples/tutorial/test_tutorial12.c100
-rw-r--r--longbow/src/examples/tutorial/test_tutorial13.c108
-rw-r--r--longbow/src/examples/tutorial/test_tutorial2.c20
-rw-r--r--longbow/src/examples/tutorial/test_tutorial3.c25
-rw-r--r--longbow/src/examples/tutorial/test_tutorial4.c35
-rw-r--r--longbow/src/examples/tutorial/test_tutorial5.c36
-rw-r--r--longbow/src/examples/tutorial/test_tutorial6.c40
-rw-r--r--longbow/src/examples/tutorial/test_tutorial7.c50
-rw-r--r--longbow/src/examples/tutorial/test_tutorial8.c52
-rw-r--r--longbow/src/examples/tutorial/test_tutorial9.c58
-rwxr-xr-xlongbow/src/examples/tutorial/tutorial.c45
-rw-r--r--longbow/src/python/.gitignore3
-rw-r--r--longbow/src/python/.project18
-rw-r--r--longbow/src/python/.pydevproject7
-rw-r--r--longbow/src/python/CMakeLists.txt29
-rwxr-xr-xlongbow/src/python/longbow-ansigcov.py85
-rwxr-xr-xlongbow/src/python/longbow-bytearray.py54
-rwxr-xr-xlongbow/src/python/longbow-code.py208
-rwxr-xr-xlongbow/src/python/longbow-complexity-report.py213
-rwxr-xr-xlongbow/src/python/longbow-coverage-report.py87
-rwxr-xr-xlongbow/src/python/longbow-doxygen-report.py166
-rwxr-xr-xlongbow/src/python/longbow-generate-about.py289
-rwxr-xr-xlongbow/src/python/longbow-name-report.py91
-rwxr-xr-xlongbow/src/python/longbow-preprocess.py153
-rwxr-xr-xlongbow/src/python/longbow-size-report.py131
-rwxr-xr-xlongbow/src/python/longbow-style-report.py99
-rwxr-xr-xlongbow/src/python/longbow-test-run.py172
-rwxr-xr-xlongbow/src/python/longbow-test-suite.py55
-rwxr-xr-xlongbow/src/python/longbow-vocabulary-report.py66
-rwxr-xr-xlongbow/src/python/parc_uncrustify.cfg115
-rw-r--r--longbow/src/python/site-packages/CMakeLists.txt12
-rwxr-xr-xlongbow/src/python/site-packages/longbow.pth18
-rw-r--r--longbow/src/python/site-packages/longbow/.gitignore1
-rwxr-xr-xlongbow/src/python/site-packages/longbow/ANSITerm.py62
-rwxr-xr-xlongbow/src/python/site-packages/longbow/CoverageReport.py262
-rwxr-xr-xlongbow/src/python/site-packages/longbow/DoxygenReport.py161
-rwxr-xr-xlongbow/src/python/site-packages/longbow/FileUtil.py102
-rwxr-xr-xlongbow/src/python/site-packages/longbow/GCov.py232
-rwxr-xr-xlongbow/src/python/site-packages/longbow/GCovSummary.py42
-rwxr-xr-xlongbow/src/python/site-packages/longbow/Language_C.py204
-rwxr-xr-xlongbow/src/python/site-packages/longbow/LongBow.py96
-rwxr-xr-xlongbow/src/python/site-packages/longbow/NameReport.py818
-rwxr-xr-xlongbow/src/python/site-packages/longbow/StyleReport.py382
-rwxr-xr-xlongbow/src/python/site-packages/longbow/SymbolTable.py87
-rwxr-xr-xlongbow/src/python/site-packages/longbow/VocabularyReport.py162
763 files changed, 180587 insertions, 0 deletions
diff --git a/README.md b/README.md
index e7f35bda..e21652fe 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+
# Introduction
The git repository structure is described in this file. It can also be derived
by scanning the repo itself. The master branch is read only and contains this
diff --git a/libparc/.gitignore b/libparc/.gitignore
new file mode 100644
index 00000000..9bdb2b73
--- /dev/null
+++ b/libparc/.gitignore
@@ -0,0 +1,67 @@
+libparc-*.tar.gz
+
+*.pyc
+*.swp
+*~
+
+# Object files
+*.o
+*.lo
+
+# Libraries
+.libs
+*.lib
+*.a
+*.la
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+=======
+LongBow
+include
+lib
+.DS_Store
+*.o
+build/
+conf.mk
+*.dSYM
+*.gcda
+*.gcno
+*.gcov
+*.a
+parc/algol/parc_LibraryVersion.c
+conf.mk
+.deps
+config.log
+config.h
+config.status
+*.log
+*.trs
+.dirstamp
+Makefile
+stamp-h1
+autom4te.cache
+
+*.xcuserdatad
+test_parc_File
+test_parc_FileInputStream
+test_parc_URIPath
+test_parc_URIAuthority
+test_parc_URISegment
+
+parc/parcLibrary_About.c
+parc/parcLibrary_About.h
+parc/parc_About.c
+parc/parc_About.h
+LDADD = ${INC_LFLAGS}
+
+libtool
+*~
diff --git a/libparc/AUTHORS b/libparc/AUTHORS
new file mode 100644
index 00000000..538e60d4
--- /dev/null
+++ b/libparc/AUTHORS
@@ -0,0 +1,11 @@
+Libparc authors are listed below
+
+ Glenn Scott <Glenn.Scott@parc.com>
+ Marc Mosko <Marc.Mosko@parc.com>
+ Kevin Fox <Kevin.Fox@parc.com>
+ Christopher Wood <woodc1@uci.edu>
+ Luca Muscariello <lumuscar@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/libparc/BASE_VERSION b/libparc/BASE_VERSION
new file mode 100644
index 00000000..d3827e75
--- /dev/null
+++ b/libparc/BASE_VERSION
@@ -0,0 +1 @@
+1.0
diff --git a/libparc/CMakeLists.txt b/libparc/CMakeLists.txt
new file mode 100644
index 00000000..3db7bfa4
--- /dev/null
+++ b/libparc/CMakeLists.txt
@@ -0,0 +1,185 @@
+cmake_minimum_required(VERSION 3.2)
+project(Libparc)
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
+set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+
+option(DOC_ONLY "Build documentation only" OFF)
+
+set(CMAKE_C_STANDARD 99)
+set(CMAKE_C_STANDARD_REQUIRED ON)
+
+if (NOT CMAKE_BUILD_TYPE)
+ message(STATUS "No build type selected, default to Release")
+ set(CMAKE_BUILD_TYPE "Release")
+endif ()
+
+if(UNIX)
+ link_libraries(m)
+endif(UNIX)
+
+include(CTest)
+include(version)
+include(detectCacheSize)
+include(CheckRealloc)
+
+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")
+elseif(COMPILE_FOR_IOS)
+ 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}")
+else()
+# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
+# set(CMAKE_C_FLAGS_NOPANTS "${CMAKE_C_FLAGS_NOPANTS} -O3 -DNDEBUG -DPARCLibrary_DISABLE_VALIDATION")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
+ find_package( Doxygen )
+endif()
+
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${CMAKE_C_FLAGS}")
+set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${CMAKE_C_FLAGS} -DPARCLibrary_DISABLE_VALIDATION -DLongBow_DISABLE_ASSERTIONS")
+set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${CMAKE_C_FLAGS}")
+set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} ${CMAKE_C_FLAGS}")
+
+include_directories($ENV{CCNX_DEPENDENCIES}/include)
+set(OPENSSL_ROOT_DIR $ENV{CCNX_DEPENDENCIES})
+
+include_directories(${PROJECT_BINARY_DIR}/parc ${PROJECT_SOURCE_DIR})
+
+if (DOC_ONLY)
+ message("############ Skipping check of required dependencies.")
+elseif(COMPILE_FOR_IOS)
+ find_host_package( LongBow REQUIRED )
+ include_directories(${LONGBOW_INCLUDE_DIRS})
+
+ find_host_package( LibEvent REQUIRED )
+ include_directories(${LIBEVENT_INCLUDE_DIRS})
+
+ find_host_package ( OpenSSL REQUIRED )
+else()
+ find_package( LongBow REQUIRED )
+ include_directories(${LONGBOW_INCLUDE_DIRS})
+
+ find_package( LibEvent REQUIRED )
+ include_directories(${LIBEVENT_INCLUDE_DIRS})
+
+ find_package ( Threads REQUIRED )
+
+ find_package ( OpenSSL REQUIRED )
+ include_directories(${OPENSSL_INCLUDE_DIR})
+endif()
+
+set(PARC_BIN_LIBRARIES
+ parc
+ ${LONGBOW_LIBRARIES}
+ ${LIBEVENT_LIBRARIES}
+ ${OPENSSL_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ )
+
+set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
+
+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)
+elseif(COMPILE_FOR_IOS)
+ macro(AddTest testFile)
+ message("iOS build: Skipping test ${ARGV0}")
+ endmacro(AddTest)
+else()
+ macro(AddTest testFile)
+ add_executable(${ARGV0} ${ARGV0}.c)
+ target_link_libraries(${ARGV0} ${PARC_BIN_LIBRARIES})
+ add_test(NAME ${ARGV0} COMMAND ${ARGV0})
+ set_target_properties(${ARGV0} PROPERTIES FOLDER Test)
+ add_dependencies(${ARGV0} ${PROJECT_NAME}_cleanup_profiling_data)
+ endmacro(AddTest)
+endif()
+
+add_subdirectory(parc)
+add_subdirectory(documentation)
+
+# Generate DEB / RPM packages
+
+option(DEB_PACKAGE "Create deb package" OFF)
+option(RPM_PACKAGE "Create deb package" OFF)
+
+set(VENDOR "Cisco Systems" CACHE STRING "Vendor")
+set(CONTACT "msardara@cisco.com" CACHE STRING "Contact")
+set(DISTRIBUTION "xenial" CACHE STRING "Distribution")
+set(ARCHITECTURE "amd64" CACHE STRING "Architecture")
+set(PACKAGE_MAINTAINER "Mauro Sardara (msardara@cisco.com)" CACHE STRING "Maintainer")
+string(TOLOWER ${CMAKE_PROJECT_NAME} PACKAGE_NAME)
+set(CPACK_PACKAGING_INSTALL_PREFIX "/usr")
+set(CPACK_PACKAGE_VENDOR ${VENDOR})
+set(CPACK_PACKAGE_CONTACT ${CONTACT})
+set(CPACK_COMPONENTS_ALL library headers documentation)
+
+# Get the version
+execute_process(COMMAND bash ${CMAKE_SOURCE_DIR}/scripts/version
+ OUTPUT_VARIABLE PACKAGE_VERSION)
+
+if (PACKAGE_VERSION)
+ string(STRIP ${PACKAGE_VERSION} PACKAGE_VERSION)
+else()
+ set(PACKAGE_VERSION 1.0)
+endif()
+
+if(DEB_PACKAGE)
+ set(TYPE "DEBIAN")
+ set(GENERATOR "DEB")
+
+ set(CPACK_${TYPE}_LIBRARY_PACKAGE_NAME "${PACKAGE_NAME}")
+ set(CPACK_${TYPE}_HEADERS_PACKAGE_NAME "${PACKAGE_NAME}-dev")
+ set(CPACK_${TYPE}_DOCUMENTATION_PACKAGE_NAME "${PACKAGE_NAME}-doc")
+
+ set(CPACK_${TYPE}_LIBRARY_FILE_NAME "${PACKAGE_NAME}_${PACKAGE_VERSION}_${ARCHITECTURE}.deb")
+ set(CPACK_${TYPE}_HEADERS_FILE_NAME "${PACKAGE_NAME}-dev_${PACKAGE_VERSION}_${ARCHITECTURE}.deb")
+ set(CPACK_${TYPE}_DOCUMENTATION_FILE_NAME "${PACKAGE_NAME}-doc_${PACKAGE_VERSION}_${ARCHITECTURE}.deb")
+
+# set(CPACK_DEBIAN_LIBRARY_PACKAGE_SHLIBDEPS ON)
+
+ set(CPACK_${TYPE}_LIBRARY_PACKAGE_DEPENDS "longbow (>= 1.0)")
+ set(CPACK_${TYPE}_HEADERS_PACKAGE_DEPENDS "libparc (>= 1.0), longbow-dev (>= 1.0), libevent-dev, libssl-dev")
+ set(CPACK_${TYPE}_DOCUMENTATION_PACKAGE_DEPENDS "")
+elseif(RPM_PACKAGE)
+ set(TYPE "RPM")
+ set(GENERATOR "RPM")
+
+ set(CPACK_${TYPE}_LIBRARY_PACKAGE_NAME "${PACKAGE_NAME}")
+ set(CPACK_${TYPE}_HEADERS_PACKAGE_NAME "${PACKAGE_NAME}-devel")
+ set(CPACK_${TYPE}_DOCUMENTATION_PACKAGE_NAME "${PACKAGE_NAME}-doc")
+
+ set(CPACK_${TYPE}_LIBRARY_FILE_NAME "${PACKAGE_NAME}-${PACKAGE_VERSION}.${ARCHITECTURE}.rpm")
+ set(CPACK_${TYPE}_HEADERS_FILE_NAME "${PACKAGE_NAME}-devel-${PACKAGE_VERSION}.${ARCHITECTURE}.rpm")
+ set(CPACK_${TYPE}_DOCUMENTATION_FILE_NAME "${PACKAGE_NAME}-doc-${PACKAGE_VERSION}.${ARCHITECTURE}.rpm")
+
+ set(CPACK_${TYPE}_LIBRARY_PACKAGE_AUTOREQ ON)
+
+ set(CPACK_${TYPE}_LIBRARY_PACKAGE_REQUIRES "longbow >= 1.0")
+ set(CPACK_${TYPE}_HEADERS_PACKAGE_REQUIRES "libparc >= 1.0, longbow-devel >= 1.0, libevent-devel, openssl-devel")
+ set(CPACK_${TYPE}_DOCUMENTATION_PACKAGE_REQUIRES "")
+
+ set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/usr/etc" "/usr/lib/python2.7" "/usr/lib/python2.7/site-packages")
+else()
+ return()
+endif()
+
+set(CPACK_GENERATOR ${GENERATOR})
+set(CPACK_${GENERATOR}_COMPONENT_INSTALL ON)
+set(CPACK_${TYPE}_PACKAGE_MAINTAINER ${PACKAGE_MAINTAINER})
+set(CPACK_${TYPE}_PACKAGE_NAME ${PACKAGE_NAME})
+set(CPACK_${TYPE}_PACKAGE_VERSION ${PACKAGE_VERSION})
+set(CPACK_${TYPE}_PACKAGE_ARCHITECTURE ${ARCHITECTURE})
+set(CPACK_${TYPE}_PACKAGE_RELEASE 1)
+set(CPACK_${TYPE}_PACKAGE_VENDOR ${VENDOR})
+set(CPACK_${TYPE}_PACKAGE_DESCRIPTION "The PARC Library is a C runtime providing an array of features and capabilities for C programs and programmers.")
+set(CPACK_${TYPE}_PACKAGE_HOMEPAGE "https://wiki.fd.io/view/Cframework")
+
+include(CPack)
diff --git a/libparc/LICENSE b/libparc/LICENSE
new file mode 100644
index 00000000..318b3f59
--- /dev/null
+++ b/libparc/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/libparc/README.md b/libparc/README.md
new file mode 100644
index 00000000..818435f6
--- /dev/null
+++ b/libparc/README.md
@@ -0,0 +1,94 @@
+Libparc
+=======
+The PARC C Library
+
+
+## Quick Start ##
+```
+
+$ git clone -b cframework/master https://gerrit.fd.io/r/cicn cframework
+$ cd cframework/libparc
+$ mkdir build
+$ cd build
+$ cmake ..
+or, for MacOSX 10.12, you need to speficy openssl root folder
+$ cmake .. -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl/
+$ make
+$ make test
+$ make install
+```
+
+## Introduction ##
+
+The PARC Library is a C runtime providing an array of features and capabilities for C programs and programmers.
+
+Functionality is grouped into:
+
+* Data structures
+* Input Output
+* Memory and Buffer Management
+* Threading and Concurrency
+* Security
+* Developer Aids
+* Networking and Communication
+
+## Using Libparc ##
+
+### Platforms ###
+
+Libparc 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
+
+Documentation dependencies:
+
+- Doxygen
+
+
+### Using Libparc ###
+
+Libparc 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 libparc library.
+
+```
+LIBPARC=<directory-where-libparc-is-installed>
+
+-I${LIBPARC}/include -L${LIBPARC}/lib -lparc
+```
+
+
+### 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/libparc/cmake/Modules/CheckRealloc.cmake b/libparc/cmake/Modules/CheckRealloc.cmake
new file mode 100644
index 00000000..191629e9
--- /dev/null
+++ b/libparc/cmake/Modules/CheckRealloc.cmake
@@ -0,0 +1,16 @@
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+include(CheckFunctionExists)
+
+CHECK_FUNCTION_EXISTS(realloc HAVE_REALLOC) \ No newline at end of file
diff --git a/libparc/cmake/Modules/FindLibEvent.cmake b/libparc/cmake/Modules/FindLibEvent.cmake
new file mode 100644
index 00000000..28a00eb2
--- /dev/null
+++ b/libparc/cmake/Modules/FindLibEvent.cmake
@@ -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.
+
+########################################
+#
+# 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/libparc/cmake/Modules/FindLongBow.cmake b/libparc/cmake/Modules/FindLongBow.cmake
new file mode 100644
index 00000000..38aef580
--- /dev/null
+++ b/libparc/cmake/Modules/FindLongBow.cmake
@@ -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.
+
+########################################
+#
+# 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/libparc/cmake/Modules/FindUncrustify.cmake b/libparc/cmake/Modules/FindUncrustify.cmake
new file mode 100644
index 00000000..00d0061f
--- /dev/null
+++ b/libparc/cmake/Modules/FindUncrustify.cmake
@@ -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.
+
+# Find uncrustify program
+#
+find_program( UNCRUSTIFY_BIN uncrustify
+ PATHS
+ $ENV{UNCRUSTIFY_HOME}
+ )
+
+message( "-- UNCRUSTIFY found in ${UNCRUSTIFY_BIN}" )
diff --git a/libparc/cmake/Modules/detectCacheSize.cmake b/libparc/cmake/Modules/detectCacheSize.cmake
new file mode 100644
index 00000000..0544c455
--- /dev/null
+++ b/libparc/cmake/Modules/detectCacheSize.cmake
@@ -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.
+
+# 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()
+
+
+if ( ${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm" )
+ set(LEVEL1_DCACHE_LINESIZE 64)
+endif()
+
+message("-- Cache line size: ${LEVEL1_DCACHE_LINESIZE}")
diff --git a/libparc/cmake/Modules/version.cmake b/libparc/cmake/Modules/version.cmake
new file mode 100644
index 00000000..120df2d0
--- /dev/null
+++ b/libparc/cmake/Modules/version.cmake
@@ -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.
+
+#
+# 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/libparc/cmake/get_version.sh b/libparc/cmake/get_version.sh
new file mode 100755
index 00000000..34c6ddb2
--- /dev/null
+++ b/libparc/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/libparc/documentation/.gitignore b/libparc/documentation/.gitignore
new file mode 100644
index 00000000..4fe1bda8
--- /dev/null
+++ b/libparc/documentation/.gitignore
@@ -0,0 +1,2 @@
+libparc.doctags
+libparc-documentation
diff --git a/libparc/documentation/CMakeLists.txt b/libparc/documentation/CMakeLists.txt
new file mode 100644
index 00000000..8c567e74
--- /dev/null
+++ b/libparc/documentation/CMakeLists.txt
@@ -0,0 +1,45 @@
+find_package(Doxygen)
+cmake_minimum_required(VERSION 3.2)
+if(DOXYGEN_FOUND)
+ set(PARC_REMOTE http://githubenterprise.parc.com/CCNX/Libparc)
+ set(GITHUB_REMOTE http://github.com/PARC/Libparc)
+ configure_file(libparc.doxygen.in config.doxygen @ONLY)
+
+ install(DIRECTORY images/ DESTINATION ${CMAKE_INSTALL_PREFIX}/share/libparc/images COMPONENT documentation)
+ install(DIRECTORY doxygen-extras/ DESTINATION ${CMAKE_INSTALL_PREFIX}/share/libparc/doxygen-extras COMPONENT documentation)
+ install(DIRECTORY examples/ DESTINATION ${CMAKE_INSTALL_PREFIX}/share/libparc/examples COMPONENT documentation)
+ install(FILES DoxygenLayout.xml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/libparc/ COMPONENT documentation)
+
+ 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 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
+ DEPENDS ${HTML_PATH}/.git/config
+ WORKING_DIRECTORY ${HTML_PATH}
+ COMMAND git push parc gh-pages -f)
+
+ add_custom_target(documentation-install-github
+ DEPENDS ${HTML_PATH}/.git/config
+ WORKING_DIRECTORY ${HTML_PATH}
+ COMMAND git push github gh-pages -f)
+
+endif(DOXYGEN_FOUND)
diff --git a/libparc/documentation/DoxygenLayout.xml b/libparc/documentation/DoxygenLayout.xml
new file mode 100644
index 00000000..759a9cd4
--- /dev/null
+++ b/libparc/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/libparc/documentation/Makefile.am b/libparc/documentation/Makefile.am
new file mode 100644
index 00000000..4163756c
--- /dev/null
+++ b/libparc/documentation/Makefile.am
@@ -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.
+#
+include ../config.mk
+
+docs: doxygen-libparc
+
+doxygen-libparc: libparc.doxygen
+
+ ${DOXYGEN_BIN} -s libparc.doxygen
+ ${prefix}/bin/longbow-doxygen-report -a --doxygenlog libparc-doxygen.log
+
+website: libparc-doxygen.log
+ $(MAKE) -C Jekyll
+
+# The Doxygen output directory removed here is set in libparc.doxygen
+clobber: clean
+ ${RM} -rf libparc-documentation
+
+CLEANFILES=libparc-doxygen.log libparc.doctags
diff --git a/libparc/documentation/Resources/parcBuffer.graffle b/libparc/documentation/Resources/parcBuffer.graffle
new file mode 100644
index 00000000..f45e9789
--- /dev/null
+++ b/libparc/documentation/Resources/parcBuffer.graffle
Binary files differ
diff --git a/libparc/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css b/libparc/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css
new file mode 100644
index 00000000..c4cadf15
--- /dev/null
+++ b/libparc/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/libparc/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css.map b/libparc/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css.map
new file mode 100644
index 00000000..016a8dab
--- /dev/null
+++ b/libparc/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/libparc/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.min.css b/libparc/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.min.css
new file mode 100644
index 00000000..4c3e7bad
--- /dev/null
+++ b/libparc/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/libparc/documentation/doxygen-extras/bootstrap/css/bootstrap.css b/libparc/documentation/doxygen-extras/bootstrap/css/bootstrap.css
new file mode 100644
index 00000000..c6f3d210
--- /dev/null
+++ b/libparc/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/libparc/documentation/doxygen-extras/bootstrap/css/bootstrap.css.map b/libparc/documentation/doxygen-extras/bootstrap/css/bootstrap.css.map
new file mode 100644
index 00000000..a02f6ba0
--- /dev/null
+++ b/libparc/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/libparc/documentation/doxygen-extras/bootstrap/css/bootstrap.min.css b/libparc/documentation/doxygen-extras/bootstrap/css/bootstrap.min.css
new file mode 100644
index 00000000..b6fe4e0f
--- /dev/null
+++ b/libparc/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/libparc/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.eot b/libparc/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 00000000..4a4ca865
--- /dev/null
+++ b/libparc/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.eot
Binary files differ
diff --git a/libparc/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.svg b/libparc/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 00000000..25691af8
--- /dev/null
+++ b/libparc/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/libparc/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.ttf b/libparc/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 00000000..67fa00bf
--- /dev/null
+++ b/libparc/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.ttf
Binary files differ
diff --git a/libparc/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.woff b/libparc/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 00000000..8c54182a
--- /dev/null
+++ b/libparc/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.woff
Binary files differ
diff --git a/libparc/documentation/doxygen-extras/bootstrap/js/bootstrap.js b/libparc/documentation/doxygen-extras/bootstrap/js/bootstrap.js
new file mode 100644
index 00000000..b6ac8d99
--- /dev/null
+++ b/libparc/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/libparc/documentation/doxygen-extras/bootstrap/js/bootstrap.min.js b/libparc/documentation/doxygen-extras/bootstrap/js/bootstrap.min.js
new file mode 100644
index 00000000..d8398659
--- /dev/null
+++ b/libparc/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/libparc/documentation/doxygen-extras/bootstrap/js/npm.js b/libparc/documentation/doxygen-extras/bootstrap/js/npm.js
new file mode 100644
index 00000000..bf6aa806
--- /dev/null
+++ b/libparc/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/libparc/documentation/doxygen-extras/customdoxygen.css b/libparc/documentation/doxygen-extras/customdoxygen.css
new file mode 100644
index 00000000..8560f848
--- /dev/null
+++ b/libparc/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/libparc/documentation/doxygen-extras/doxy-boot.js b/libparc/documentation/doxygen-extras/doxy-boot.js
new file mode 100644
index 00000000..5ee5fa37
--- /dev/null
+++ b/libparc/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/libparc/documentation/doxygen-extras/doxygen-bootstrap.js b/libparc/documentation/doxygen-extras/doxygen-bootstrap.js
new file mode 100755
index 00000000..2ddb6474
--- /dev/null
+++ b/libparc/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/libparc/documentation/doxygen-extras/footer.html b/libparc/documentation/doxygen-extras/footer.html
new file mode 100755
index 00000000..43f2feb1
--- /dev/null
+++ b/libparc/documentation/doxygen-extras/footer.html
@@ -0,0 +1,14 @@
+<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
+ </div>
+</body>
+</html>
diff --git a/libparc/documentation/doxygen-extras/header.html b/libparc/documentation/doxygen-extras/header.html
new file mode 100755
index 00000000..e7b5e592
--- /dev/null
+++ b/libparc/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/libparc/documentation/doxygen-extras/masthead.css b/libparc/documentation/doxygen-extras/masthead.css
new file mode 100644
index 00000000..7827e079
--- /dev/null
+++ b/libparc/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/libparc/documentation/examples/README.md b/libparc/documentation/examples/README.md
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/libparc/documentation/examples/README.md
diff --git a/libparc/documentation/images/logo_fdio.png b/libparc/documentation/images/logo_fdio.png
new file mode 100644
index 00000000..ddfef2c7
--- /dev/null
+++ b/libparc/documentation/images/logo_fdio.png
Binary files differ
diff --git a/libparc/documentation/imported-stylesheet.css b/libparc/documentation/imported-stylesheet.css
new file mode 100644
index 00000000..75f90b9a
--- /dev/null
+++ b/libparc/documentation/imported-stylesheet.css
@@ -0,0 +1 @@
+@import "../assets/css/doxygen.css";
diff --git a/libparc/documentation/libparc.doxygen b/libparc/documentation/libparc.doxygen
new file mode 100644
index 00000000..fc9d6483
--- /dev/null
+++ b/libparc/documentation/libparc.doxygen
@@ -0,0 +1,2392 @@
+# 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 = "PARC 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 = libparc-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 = NO
+
+# 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 = libparc-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 = ../parc/algol \
+ ../parc/security \
+ ../parc/logging \
+ ../parc/concurrent \
+ ../parc/logging
+
+# 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 = ../parc/algol/test \
+ ../parc/security/test \
+ ../parc/concurrent/test \
+ ../parc/logging/test
+
+# 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 = 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 = 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 = doxygen-extras/customdoxygen.css 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 = doxygen-extras/doxygen-bootstrap.js images/logo_fdio.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 = YES
+
+# 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=
+
+# 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 = libparc.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/libparc/documentation/libparc.doxygen.in b/libparc/documentation/libparc.doxygen.in
new file mode 100644
index 00000000..1844b3e2
--- /dev/null
+++ b/libparc/documentation/libparc.doxygen.in
@@ -0,0 +1,2397 @@
+# 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 = "PARC 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 = ../parc/algol \
+# ../parc/security \
+# ../parc/logging \
+# ../parc/concurrent \
+# ../parc/logging
+
+INPUT = @CMAKE_CURRENT_SOURCE_DIR@/../parc/algol \
+ @CMAKE_CURRENT_SOURCE_DIR@/../parc/security \
+ @CMAKE_CURRENT_SOURCE_DIR@/../parc/logging \
+ @CMAKE_CURRENT_SOURCE_DIR@/../parc/concurrent \
+ @CMAKE_CURRENT_SOURCE_DIR@/../parc/logging
+# 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 = ../parc/algol/test \
+ ../parc/security/test \
+ ../parc/concurrent/test \
+ ../parc/logging/test
+
+# 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/logo_fdio.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 = libparc.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/libparc/examples/How To Create A Static PARC Object/main.c b/libparc/examples/How To Create A Static PARC Object/main.c
new file mode 100755
index 00000000..00402170
--- /dev/null
+++ b/libparc/examples/How To Create A Static PARC Object/main.c
@@ -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.
+ */
+
+#include <stdio.h>
+
+#include <parc/algol/parc_Memory.h>
+#include "parc_MyObject.h"
+
+/*
+ * Three kinds of static PARC Objects
+ *
+ * static or global objects defined within a module
+ *
+ * local objects defined within a function.
+ *
+ */
+
+PARCMyObject *globalObject = parcObject_Instance(PARCMyObject, sizeof(void*), PARCMyObjectSizeOf);
+
+void
+aGlobalObject(void)
+{
+ int x = 1;
+ int y = 2;
+ double z = 3.14;
+
+ parcObject_InitInstance(globalObject, PARCMyObject);
+ parcMyObject_Init(globalObject, x, y, z);
+
+ parcMyObject_Display(globalObject, 0);
+
+ parcMyObject_Release(&globalObject);
+}
+
+static PARCMyObject *staticModuleObject = parcObject_Instance(PARCMyObject, sizeof(void*), PARCMyObjectSizeOf);
+
+void
+aStaticModuleObject(void)
+{
+ int x = 1;
+ int y = 2;
+ double z = 3.14;
+
+ parcObject_InitInstance(staticModuleObject, PARCMyObject);
+ parcMyObject_Init(staticModuleObject, x, y, z);
+
+ parcMyObject_Display(staticModuleObject, 0);
+
+ parcMyObject_Release(&staticModuleObject);
+}
+
+void
+aLocalObject(void)
+{
+ int x = 1;
+ int y = 2;
+ double z = 3.14;
+
+ PARCMyObject *localObject = parcObject_Instance(PARCMyObject, sizeof(void*), PARCMyObjectSizeOf);
+
+ parcObject_InitInstance(localObject, PARCMyObject);
+ parcMyObject_Init(localObject, x, y, z);
+
+ parcMyObject_Display(localObject, 0);
+
+ parcMyObject_Release(&localObject);
+}
+
+void
+aWrappedObject(void)
+{
+ int x = 1;
+ int y = 2;
+ double z = 3.14;
+
+ PARCMyObject *wrappedObject = parcMyObject_Wrap((char[parcObject_TotalSize(sizeof(void*), PARCMyObjectSizeOf)]) { 0 });
+ parcMyObject_Init(wrappedObject, x, y, z);
+
+ parcMyObject_Display(wrappedObject, 0);
+
+ parcMyObject_Release(&wrappedObject);
+}
+
+int
+main(int argc, const char *argv[argc])
+{
+ aGlobalObject();
+
+ aStaticModuleObject();
+
+ aLocalObject();
+
+ aWrappedObject();
+
+ return 0;
+}
diff --git a/libparc/examples/How To Create A Static PARC Object/parc_MyObject.c b/libparc/examples/How To Create A Static PARC Object/parc_MyObject.c
new file mode 100644
index 00000000..9523e494
--- /dev/null
+++ b/libparc/examples/How To Create A Static PARC Object/parc_MyObject.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "parc_MyObject.h"
+
+// Detect a compile time if a buffer is large enough to hold a structure.
+#define parcObject_DefineXXX(_type_, ...) \
+ typedef struct { __VA_ARGS__ } _ ## _type_; \
+ enum { bytesCompileTimeAssertion = 1 / !!(sizeof(_type_) >= sizeof(_ ## _type_)) }
+
+struct PARCMyObject {
+ int x;
+ double y;
+ double z;
+};
+
+static bool
+_parcMyObject_Destructor(PARCMyObject **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCMyObject pointer.");
+
+
+ /* cleanup the instance fields here */
+ return true;
+}
+
+parcObject_ImplementAcquire(parcMyObject, PARCMyObject);
+
+parcObject_ImplementRelease(parcMyObject, PARCMyObject);
+
+parcObject_Override(
+ PARCMyObject, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcMyObject_Destructor,
+ .copy = (PARCObjectCopy *) parcMyObject_Copy,
+ .toString = (PARCObjectToString *) parcMyObject_ToString,
+ .equals = (PARCObjectEquals *) parcMyObject_Equals,
+ .compare = (PARCObjectCompare *) parcMyObject_Compare,
+ .hashCode = (PARCObjectHashCode *) parcMyObject_HashCode,
+ .toJSON = (PARCObjectToJSON *) parcMyObject_ToJSON);
+
+
+void
+parcMyObject_AssertValid(const PARCMyObject *instance)
+{
+ assertTrue(parcMyObject_IsValid(instance),
+ "PARCMyObject is not valid.");
+}
+
+PARCMyObject *
+parcMyObject_Wrap(void *origin)
+{
+ PARCMyObject *result = parcObject_Wrap(origin, PARCMyObject);
+
+ return result;
+}
+
+PARCMyObject *
+parcMyObject_Init(PARCMyObject *object, int x, double y, double z)
+{
+ if (object != NULL) {
+ object->x = x;
+ object->y = y;
+ object->z = z;
+ }
+
+ return object;
+}
+
+PARCMyObject *
+parcMyObject_Create(int x, double y, double z)
+{
+ PARCMyObject *result = parcObject_CreateInstance(PARCMyObject);
+
+ if (result != NULL) {
+ result->x = x;
+ result->y = y;
+ result->z = z;
+ }
+
+ return (PARCMyObject *) result;
+}
+
+int
+parcMyObject_Compare(const PARCMyObject *instance, const PARCMyObject *other)
+{
+ int result = 0;
+
+ return result;
+}
+
+PARCMyObject *
+parcMyObject_Copy(const PARCMyObject *original)
+{
+ PARCMyObject *result = NULL;
+
+ return result;
+}
+
+void
+parcMyObject_Display(const PARCMyObject *object, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCMyObject@%p { .x=%d .y=%f .z=%f }", object, object->x, object->y, object->z);
+}
+
+bool
+parcMyObject_Equals(const PARCMyObject *x, const PARCMyObject *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
+parcMyObject_HashCode(const PARCMyObject *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+parcMyObject_IsValid(const PARCMyObject *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcMyObject_ToJSON(const PARCMyObject *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ if (result != NULL) {
+ }
+
+ return result;
+}
+
+char *
+parcMyObject_ToString(const PARCMyObject *object)
+{
+ char *result = parcMemory_Format("PARCMyObject@%p { .x=%d .y=%f .z=%f }", object, object->x, object->y, object->z);
+
+ return result;
+}
diff --git a/libparc/examples/How To Create A Static PARC Object/parc_MyObject.h b/libparc/examples/How To Create A Static PARC Object/parc_MyObject.h
new file mode 100644
index 00000000..124e734e
--- /dev/null
+++ b/libparc/examples/How To Create A Static PARC Object/parc_MyObject.h
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_MyObject.h
+ * @brief A simple example of how to create static, not allocataed, PARC Objects.
+ *
+ */
+#ifndef PARCLibrary_parc_MyObject
+#define PARCLibrary_parc_MyObject
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+parcObject_Declare(PARCMyObject);
+
+/**
+ * The number of bytes sufficient to contain the MyObject data.
+ *
+ * This is dependant upon the definition of the underlying `struct MyObject`.
+ * If that definition changes, it may be necessary to change this constant.
+ */
+#define PARCMyObjectSizeOf 24
+
+/**
+ * Increase the number of references to a `PARCMyObject` instance.
+ *
+ * Note that new `PARCMyObject` is not created,
+ * only that the given `PARCMyObject` reference count is incremented.
+ * Discard the reference by invoking `parcMyObject_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCMyObject instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCMyObject *a = parcMyObject_Create();
+ *
+ * PARCMyObject *b = parcMyObject_Acquire();
+ *
+ * parcMyObject_Release(&a);
+ * parcMyObject_Release(&b);
+ * }
+ * @endcode
+ */
+PARCMyObject *parcMyObject_Acquire(const PARCMyObject *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcMyObject_OptionalAssertValid(_instance_)
+#else
+# define parcMyObject_OptionalAssertValid(_instance_) parcMyObject_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCMyObject` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCMyObject instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCMyObject *a = parcMyObject_Create();
+ *
+ * parcMyObject_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcMyObject_Release(&b);
+ * }
+ * @endcode
+ */
+void parcMyObject_AssertValid(const PARCMyObject *instance);
+
+/**
+ * Create an instance of PARCMyObject
+ *
+ * @return non-NULL A pointer to a valid PARCMyObject instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCMyObject *a = parcMyObject_Create();
+ *
+ * parcMyObject_Release(&a);
+ * }
+ * @endcode
+ */
+PARCMyObject *parcMyObject_Create(int x, double y, double z);
+
+/**
+ * Set a PARCMyObject instance to it's initial, created state.
+ *
+ * @return non-NULL A pointer to a valid PARCMyObject instance.
+ * @return NULL An error occurred.
+ */
+PARCMyObject *parcMyObject_Init(PARCMyObject *instance, int x, double y, double z);
+
+PARCMyObject *parcMyObject_Wrap(void *origin);
+
+/**
+ * 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 PARCMyObject instance.
+ * @param [in] other A pointer to a valid PARCMyObject 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
+ * {
+ * PARCMyObject *a = parcMyObject_Create();
+ * PARCMyObject *b = parcMyObject_Create();
+ *
+ * if (parcMyObject_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcMyObject_Release(&a);
+ * parcMyObject_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcMyObject_Equals
+ */
+int parcMyObject_Compare(const PARCMyObject *instance, const PARCMyObject *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 PARCMyObject instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCMyObject` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCMyObject *a = parcMyObject_Create();
+ *
+ * PARCMyObject *copy = parcMyObject_Copy(&b);
+ *
+ * parcMyObject_Release(&b);
+ * parcMyObject_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCMyObject *parcMyObject_Copy(const PARCMyObject *original);
+
+/**
+ * Print a human readable representation of the given `PARCMyObject`.
+ *
+ * @param [in] instance A pointer to a valid PARCMyObject instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCMyObject *a = parcMyObject_Create();
+ *
+ * parcMyObject_Display(a, 0);
+ *
+ * parcMyObject_Release(&a);
+ * }
+ * @endcode
+ */
+void parcMyObject_Display(const PARCMyObject *instance, int indentation);
+
+/**
+ * Determine if two `PARCMyObject` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCMyObject` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcMyObject_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcMyObject_Equals(x, y)` must return true if and only if
+ * `parcMyObject_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcMyObject_Equals(x, y)` returns true and
+ * `parcMyObject_Equals(y, z)` returns true,
+ * then `parcMyObject_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcMyObject_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcMyObject_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCMyObject instance.
+ * @param [in] y A pointer to a valid PARCMyObject instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCMyObject *a = parcMyObject_Create();
+ * PARCMyObject *b = parcMyObject_Create();
+ *
+ * if (parcMyObject_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcMyObject_Release(&a);
+ * parcMyObject_Release(&b);
+ * }
+ * @endcode
+ * @see parcMyObject_HashCode
+ */
+bool parcMyObject_Equals(const PARCMyObject *x, const PARCMyObject *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 parcMyObject_Equals} method,
+ * then calling the {@link parcMyObject_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 parcMyObject_Equals} function,
+ * then calling the `parcMyObject_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCMyObject instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCMyObject *a = parcMyObject_Create();
+ *
+ * PARCHashCode hashValue = parcMyObject_HashCode(buffer);
+ * parcMyObject_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcMyObject_HashCode(const PARCMyObject *instance);
+
+/**
+ * Determine if an instance of `PARCMyObject` 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 PARCMyObject instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCMyObject *a = parcMyObject_Create();
+ *
+ * if (parcMyObject_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcMyObject_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcMyObject_IsValid(const PARCMyObject *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCMyObject` 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
+ * {
+ * PARCMyObject *a = parcMyObject_Create();
+ *
+ * parcMyObject_Release(&a);
+ * }
+ * @endcode
+ */
+void parcMyObject_Release(PARCMyObject **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCMyObject 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
+ * {
+ * PARCMyObject *a = parcMyObject_Create();
+ *
+ * PARCJSON *json = parcMyObject_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcMyObject_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcMyObject_ToJSON(const PARCMyObject *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCMyObject`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCMyObject 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
+ * {
+ * PARCMyObject *a = parcMyObject_Create();
+ *
+ * char *string = parcMyObject_ToString(a);
+ *
+ * parcMyObject_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcMyObject_Display
+ */
+char *parcMyObject_ToString(const PARCMyObject *instance);
+
+#endif
diff --git a/libparc/examples/How To Create an Object Pool/main.c b/libparc/examples/How To Create an Object Pool/main.c
new file mode 100644
index 00000000..710d3d7c
--- /dev/null
+++ b/libparc/examples/How To Create an Object Pool/main.c
@@ -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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "parc_SimpleBufferPool.h"
+
+int
+main(int argc, char *argv[argc])
+{
+ PARCSimpleBufferPool *pool = parcSimpleBufferPool_Create(3, 10);
+
+ PARCBuffer *buffer = parcSimpleBufferPool_GetInstance(pool);
+ parcBuffer_Release(&buffer);
+
+ buffer = parcSimpleBufferPool_GetInstance(pool);
+ parcBuffer_Release(&buffer);
+
+ parcSimpleBufferPool_Release(&pool);
+
+ return 0;
+}
diff --git a/libparc/examples/How To Create an Object Pool/parc_SimpleBufferPool.c b/libparc/examples/How To Create an Object Pool/parc_SimpleBufferPool.c
new file mode 100644
index 00000000..fbd71b6e
--- /dev/null
+++ b/libparc/examples/How To Create an Object Pool/parc_SimpleBufferPool.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 <stdio.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_LinkedList.h>
+
+#include "parc_SimpleBufferPool.h"
+
+struct PARCSimpleBufferPool {
+ size_t bufferSize;
+ size_t limit;
+ PARCLinkedList *freeList;
+ PARCObjectDescriptor *descriptor;
+};
+
+static bool
+_parcSimpleBufferPool_Destructor(PARCSimpleBufferPool **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCSimpleBufferPool pointer.");
+
+ PARCSimpleBufferPool *pool = *instancePtr;
+
+ parcLinkedList_Apply(pool->freeList, (void (*))parcObject_SetDescriptor, (const void *) &PARCBuffer_Descriptor);
+
+ parcLinkedList_Release(&pool->freeList);
+
+ return true;
+}
+
+static bool
+_parcSimpleBufferPool_BufferDestructor(PARCBuffer **bufferPtr)
+{
+ PARCBuffer *buffer = *bufferPtr;
+ *bufferPtr = 0;
+
+ PARCSimpleBufferPool *bufferPool = parcObjectDescriptor_GetTypeState(parcObject_GetDescriptor(buffer));
+
+ if (bufferPool->limit > parcLinkedList_Size(bufferPool->freeList)) {
+ parcLinkedList_Append(bufferPool->freeList, buffer);
+ } else {
+ parcBuffer_Acquire(buffer);
+ parcObject_SetDescriptor(buffer, &parcObject_DescriptorName(PARCBuffer));
+ parcBuffer_Release(&buffer);
+ }
+
+ return false;
+}
+
+parcObject_ImplementAcquire(parcSimpleBufferPool, PARCSimpleBufferPool);
+
+parcObject_ImplementRelease(parcSimpleBufferPool, PARCSimpleBufferPool);
+
+parcObject_Override(PARCSimpleBufferPool, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcSimpleBufferPool_Destructor);
+
+PARCSimpleBufferPool *
+parcSimpleBufferPool_Create(size_t limit, size_t bufferSize)
+{
+ PARCSimpleBufferPool *result = parcObject_CreateInstance(PARCSimpleBufferPool);
+
+ if (result != NULL) {
+ result->limit = limit;
+ result->bufferSize = bufferSize;
+ result->freeList = parcLinkedList_Create();
+
+ char *string;
+ asprintf(&string, "PARCSimpleBufferPool=%zu", bufferSize);
+ result->descriptor = parcObjectDescriptor_CreateExtension(&parcObject_DescriptorName(PARCBuffer), string);
+ free(string);
+ result->descriptor->destructor = (PARCObjectDestructor *) _parcSimpleBufferPool_BufferDestructor;
+ result->descriptor->typeState = (PARCObjectTypeState *) result;
+ }
+
+ return result;
+}
+
+PARCBuffer *
+parcSimpleBufferPool_GetInstance(PARCSimpleBufferPool *bufferPool)
+{
+ PARCBuffer *result;
+
+ if (parcLinkedList_Size(bufferPool->freeList) > 0) {
+ result = parcLinkedList_RemoveFirst(bufferPool->freeList);
+ } else {
+ result = parcBuffer_Allocate(bufferPool->bufferSize);
+ parcObject_SetDescriptor(result, bufferPool->descriptor);
+ }
+
+ return result;
+}
diff --git a/libparc/examples/How To Create an Object Pool/parc_SimpleBufferPool.h b/libparc/examples/How To Create an Object Pool/parc_SimpleBufferPool.h
new file mode 100644
index 00000000..fe8ddf4a
--- /dev/null
+++ b/libparc/examples/How To Create an Object Pool/parc_SimpleBufferPool.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 parc_BufferPool.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_BufferPool
+#define PARCLibrary_parc_BufferPool
+#include <stdbool.h>
+
+#include <parc/algol/parc_Object.h>
+
+parcObject_Declare(PARCSimpleBufferPool);
+
+/**
+ * Increase the number of references to a `PARCBufferPool` instance.
+ *
+ * Note that new `PARCBufferPool` is not created,
+ * only that the given `PARCBufferPool` reference count is incremented.
+ * Discard the reference by invoking `parcSimpleBufferPool_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCBufferPool instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferPool *a = parcSimpleBufferPool_Create();
+ *
+ * PARCBufferPool *b = parcSimpleBufferPool_Acquire();
+ *
+ * parcSimpleBufferPool_Release(&a);
+ * parcSimpleBufferPool_Release(&b);
+ * }
+ * @endcode
+ */
+PARCSimpleBufferPool *parcSimpleBufferPool_Acquire(const PARCSimpleBufferPool *instance);
+
+/**
+ * Create an instance of PARCBufferPool
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCBufferPool instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferPool *a = parcSimpleBufferPool_Create();
+ *
+ * parcSimpleBufferPool_Release(&a);
+ * }
+ * @endcode
+ */
+PARCSimpleBufferPool *parcSimpleBufferPool_Create(size_t highWater, size_t bufferSize);
+
+/**
+ * Release a previously acquired reference to the given `PARCBufferPool` 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
+ * {
+ * PARCSimpleBufferPool *a = parcSimpleBufferPool_Create();
+ *
+ * parcSimpleBufferPool_Release(&a);
+ * }
+ * @endcode
+ */
+void parcSimpleBufferPool_Release(PARCSimpleBufferPool **instancePtr);
+
+PARCBuffer *parcSimpleBufferPool_GetInstance(PARCSimpleBufferPool *bufferPool);
+
+#endif
diff --git a/libparc/examples/How To Extend a PARCObject/HowToExtendAPARCObject.c b/libparc/examples/How To Extend a PARCObject/HowToExtendAPARCObject.c
new file mode 100644
index 00000000..e98018d7
--- /dev/null
+++ b/libparc/examples/How To Extend a PARCObject/HowToExtendAPARCObject.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.
+ */
+
+/**
+ *
+ * This example shows a simple extention of an existing PARC Object implementation
+ * (PARCString) to replace the default implementation of the Compare() function with another.
+ *
+ * The demonstration shows how to reverse the sort order of a PARCSortedList
+ * containing a list of PARCString instances without changing PARCSortedList nor PARCString.
+ *
+ */
+#include <stdio.h>
+
+#include <parc/algol/parc_SortedList.h>
+#include <parc/algol/parc_String.h>
+
+/*
+ * This is the default behaviour of the PARCSortedList implementation.
+ */
+void
+forwardOrder(void)
+{
+ PARCSortedList *sortedList = parcSortedList_Create();
+
+ PARCString *aaa = parcString_Create("aaa");
+ PARCString *aab = parcString_Create("aab");
+ PARCString *aac = parcString_Create("aac");
+
+ parcSortedList_Add(sortedList, aaa);
+ parcSortedList_Add(sortedList, aab);
+ parcSortedList_Add(sortedList, aac);
+
+ parcSortedList_Display(sortedList, 0);
+ parcString_Release(&aaa);
+ parcString_Release(&aab);
+ parcString_Release(&aac);
+}
+
+/*
+ * This function will be substituted for the default Compare implementation in the PARCString object.
+ */
+int
+parcString_ReverseCompare(const PARCString *string, const PARCString *other)
+{
+ return parcString_Compare(string, other) * -1;
+}
+
+parcObject_Extends(PARCReverseString, PARCString,
+ .compare = (PARCObjectCompare *) parcString_ReverseCompare);
+
+
+PARCString *
+parcMyString_Create(const char *string)
+{
+ PARCString *result = parcString_Create(string);
+
+ // By setting the descriptor to our special descriptor here, we effectively
+ // substitute the default compare function with our parcString_ReverseCompare
+ parcObject_SetDescriptor(result, &parcObject_DescriptorName(PARCReverseString));
+
+ return result;
+}
+
+void
+reverseOrder(void)
+{
+ PARCSortedList *sortedList = parcSortedList_Create();
+
+ PARCString *aaa = parcMyString_Create("aaa");
+ PARCString *aab = parcMyString_Create("aab");
+ PARCString *aac = parcMyString_Create("aac");
+
+ parcSortedList_Add(sortedList, aaa);
+ parcSortedList_Add(sortedList, aab);
+ parcSortedList_Add(sortedList, aac);
+
+ parcSortedList_Display(sortedList, 0);
+ parcString_Release(&aaa);
+ parcString_Release(&aab);
+ parcString_Release(&aac);
+}
+
+int
+main(int argc, const char *argv[argc])
+{
+ forwardOrder();
+ reverseOrder();
+ return 0;
+}
diff --git a/libparc/parc/CMakeLists.txt b/libparc/parc/CMakeLists.txt
new file mode 100644
index 00000000..1b98fee9
--- /dev/null
+++ b/libparc/parc/CMakeLists.txt
@@ -0,0 +1,410 @@
+# Define a few configuration variables that we want accessible in the software
+
+configure_file("config.h.in" "config.h" @ONLY)
+
+set(LIBPARC_BASE_HEADER_FILES
+ libparc_About.h
+ )
+
+set(LIBPARC_ALGOL_HEADER_FILES
+ algol/parc_ArrayList.h
+ algol/parc_AtomicInteger.h
+ algol/parc_Base64.h
+ algol/parc_BitVector.h
+ algol/parc_Buffer.h
+ algol/parc_BufferChunker.h
+ algol/parc_BufferComposer.h
+ algol/parc_BufferDictionary.h
+ algol/parc_ByteArray.h
+ algol/parc_Clock.h
+ algol/parc_Chunker.h
+ algol/parc_CMacro.h
+ algol/parc_Collection.h
+ algol/parc_Deque.h
+ algol/parc_Dictionary.h
+ algol/parc_DisplayIndented.h
+ algol/parc_Environment.h
+ algol/parc_Event.h
+ algol/parc_EventScheduler.h
+ algol/parc_EventSignal.h
+ algol/parc_EventSocket.h
+ algol/parc_EventTimer.h
+ algol/parc_EventQueue.h
+ algol/parc_EventBuffer.h
+ algol/parc_Execution.h
+ algol/parc_File.h
+ algol/parc_FileChunker.h
+ algol/parc_FileInputStream.h
+ algol/parc_FileOutputStream.h
+ algol/parc_Hash.h
+ algol/parc_HashCode.h
+ algol/parc_HashCodeTable.h
+ algol/parc_HashMap.h
+ algol/parc_InputStream.h
+ algol/parc_Iterator.h
+ algol/parc_JSON.h
+ algol/parc_JSONArray.h
+ algol/parc_JSONPair.h
+ algol/parc_JSONValue.h
+ algol/parc_JSONParser.h
+ algol/parc_KeyValue.h
+ algol/parc_KeyedElement.h
+ algol/parc_List.h
+ algol/parc_LinkedList.h
+ algol/parc_Memory.h
+ algol/parc_Network.h
+ algol/parc_Object.h
+ algol/parc_OutputStream.h
+ algol/parc_PathName.h
+ algol/parc_PriorityQueue.h
+ algol/parc_Properties.h
+ algol/parc_RandomAccessFile.h
+ algol/parc_ReadOnlyBuffer.h
+ algol/parc_StdlibMemory.h
+ algol/parc_SafeMemory.h
+ algol/parc_SortedList.h
+ algol/parc_Stack.h
+ algol/parc_String.h
+ algol/parc_Time.h
+ algol/parc_TreeMap.h
+ algol/parc_TreeRedBlack.h
+ algol/parc_URI.h
+ algol/parc_URIAuthority.h
+ algol/parc_URIPath.h
+ algol/parc_URISegment.h
+ algol/parc_Varint.h
+ algol/parc_Vector.h
+ algol/parc_Unsigned.h
+ )
+
+set(LIBPARC_PRIVATE_HEADER_FILES
+ algol/internal_parc_Event.h
+ )
+
+set(LIBPARC_ALGOL_SOURCE_FILES
+ libparc_About.c
+ algol/parc_ArrayList.c
+ algol/parc_AtomicInteger.c
+ algol/parc_Base64.c
+ algol/parc_BitVector.c
+ algol/parc_Buffer.c
+ algol/parc_BufferChunker.c
+ algol/parc_BufferComposer.c
+ algol/parc_BufferDictionary.c
+ algol/parc_ByteArray.c
+ algol/parc_Clock.c
+ algol/parc_Chunker.c
+ algol/parc_Deque.c
+ algol/parc_Dictionary.c
+ algol/parc_DisplayIndented.c
+ algol/parc_Environment.c
+ algol/parc_File.c
+ algol/parc_FileChunker.c
+ algol/parc_FileInputStream.c
+ algol/parc_FileOutputStream.c
+ algol/parc_Hash.c
+ algol/parc_HashCode.c
+ algol/parc_HashCodeTable.c
+ algol/parc_InputStream.c
+ algol/parc_Iterator.c
+ algol/parc_JSON.c
+ algol/parc_JSONArray.c
+ algol/parc_JSONPair.c
+ algol/parc_JSONValue.c
+ algol/parc_JSONParser.c
+ algol/parc_KeyValue.c
+ algol/parc_KeyedElement.c
+ algol/parc_List.c
+ algol/parc_LinkedList.c
+ algol/parc_Memory.c
+ algol/internal_parc_Event.c
+ algol/parc_Event.c
+ algol/parc_EventScheduler.c
+ algol/parc_EventSignal.c
+ algol/parc_EventSocket.c
+ algol/parc_EventTimer.c
+ algol/parc_EventQueue.c
+ algol/parc_EventBuffer.c
+ algol/parc_Execution.c
+ algol/parc_HashMap.c
+ algol/parc_Network.c
+ algol/parc_Object.c
+ algol/parc_OutputStream.c
+ algol/parc_PathName.c
+ algol/parc_PriorityQueue.c
+ algol/parc_Properties.c
+ algol/parc_RandomAccessFile.c
+ algol/parc_ReadOnlyBuffer.c
+ algol/parc_SafeMemory.c
+ algol/parc_SortedList.c
+ algol/parc_StdlibMemory.c
+ algol/parc_Stack.c
+ algol/parc_String.c
+ algol/parc_Time.c
+ algol/parc_TreeMap.c
+ algol/parc_TreeRedBlack.c
+ algol/parc_URI.c
+ algol/parc_URIAuthority.c
+ algol/parc_URIPath.c
+ algol/parc_URISegment.c
+ algol/parc_Varint.c
+ algol/parc_Vector.c
+ algol/parc_Unsigned.c
+ )
+
+set(LIBPARC_TESTING_HEADER_FILES
+ testing/parc_MemoryTesting.h
+ testing/parc_ObjectTesting.h
+ )
+
+set(LIBPARC_TESTING_SOURCE_FILES
+ testing/parc_MemoryTesting.c
+ testing/parc_ObjectTesting.c
+ )
+
+set(LIBPARC_SECURITY_HEADER_FILES
+ security/parc_CryptoHasher.h
+ security/parc_CryptoHash.h
+ security/parc_CryptoHashType.h
+ security/parc_CryptoSuite.h
+ security/parc_DiffieHellman.h
+ security/parc_DiffieHellmanKeyShare.h
+ security/parc_DiffieHellmanGroup.h
+ security/parc_SigningAlgorithm.h
+ security/parc_CryptoCache.h
+ security/parc_InMemoryVerifier.h
+ security/parc_Identity.h
+ security/parc_IdentityFile.h
+ security/parc_Key.h
+ security/parc_KeyId.h
+ security/parc_KeyStore.h
+ security/parc_Pkcs12KeyStore.h
+ security/parc_PublicKeySigner.h
+ security/parc_SecureRandom.h
+ security/parc_Security.h
+ security/parc_Signature.h
+ security/parc_Signer.h
+ security/parc_SymmetricKeySigner.h
+ security/parc_SymmetricKeyStore.h
+ security/parc_Verifier.h
+ security/parc_ContainerEncoding.h
+ security/parc_Certificate.h
+ security/parc_CertificateFactory.h
+ security/parc_CertificateType.h
+ security/parc_X509Certificate.h
+ security/parc_KeyType.h
+ )
+
+set(LIBPARC_SECURITY_SOURCE_FILES
+ security/parc_CryptoHasher.c
+ security/parc_CryptoHash.c
+ security/parc_CryptoHashType.c
+ security/parc_CryptoSuite.c
+ security/parc_SigningAlgorithm.c
+ security/parc_CryptoCache.c
+ security/parc_DiffieHellman.c
+ security/parc_DiffieHellmanKeyShare.c
+ security/parc_InMemoryVerifier.c
+ security/parc_Identity.c
+ security/parc_IdentityFile.c
+ security/parc_Key.c
+ security/parc_KeyId.c
+ security/parc_KeyStore.c
+ security/parc_Pkcs12KeyStore.c
+ security/parc_PublicKeySigner.c
+ security/parc_SymmetricKeySigner.c
+ security/parc_SymmetricKeyStore.c
+ security/parc_Security.c
+ security/parc_SecureRandom.c
+ security/parc_Signature.c
+ security/parc_Signer.c
+ security/parc_Verifier.c
+ security/parc_ContainerEncoding.c
+ security/parc_Certificate.c
+ security/parc_CertificateFactory.c
+ security/parc_CertificateType.c
+ security/parc_X509Certificate.c
+ )
+
+
+set(LIBPARC_CONCURRENT_HEADER_FILES
+ concurrent/parc_AtomicUint16.h
+ concurrent/parc_AtomicUint32.h
+ concurrent/parc_AtomicUint64.h
+ concurrent/parc_AtomicUint8.h
+ concurrent/parc_FutureTask.h
+ concurrent/parc_Lock.h
+ concurrent/parc_Notifier.h
+ concurrent/parc_RingBuffer.h
+ concurrent/parc_RingBuffer_1x1.h
+ concurrent/parc_RingBuffer_NxM.h
+ concurrent/parc_ScheduledTask.h
+ concurrent/parc_ScheduledThreadPool.h
+ concurrent/parc_Synchronizer.h
+ concurrent/parc_Thread.h
+ concurrent/parc_ThreadPool.h
+ concurrent/parc_Timeout.h
+ concurrent/parc_Timer.h
+ )
+
+set(LIBPARC_CONCURRENT_SOURCE_FILES
+ concurrent/parc_AtomicUint16.c
+ concurrent/parc_AtomicUint32.c
+ concurrent/parc_AtomicUint64.c
+ concurrent/parc_AtomicUint8.c
+ concurrent/parc_FutureTask.c
+ concurrent/parc_Lock.c
+ concurrent/parc_Notifier.c
+ concurrent/parc_RingBuffer.c
+ concurrent/parc_RingBuffer_1x1.c
+ concurrent/parc_RingBuffer_NxM.c
+ concurrent/parc_ScheduledTask.c
+ concurrent/parc_ScheduledThreadPool.c
+ concurrent/parc_Synchronizer.c
+ concurrent/parc_Thread.c
+ concurrent/parc_ThreadPool.c
+ concurrent/parc_Timeout.c
+ concurrent/parc_Timer.c
+ )
+
+set(LIBPARC_LOGGING_HEADER_FILES
+ logging/parc_Log.h
+ logging/parc_LogEntry.h
+ logging/parc_LogLevel.h
+ logging/parc_LogManager.h
+ logging/parc_LogReporter.h
+ logging/parc_LogReporterFile.h
+ logging/parc_LogReporterTextStdout.h
+ logging/parc_LogFormatText.h
+ logging/parc_LogFormatSyslog.h
+ )
+
+set(LIBPARC_LOGGING_SOURCE_FILES
+ logging/parc_Log.c
+ logging/parc_LogEntry.c
+ logging/parc_LogLevel.c
+ logging/parc_LogManager.c
+ logging/parc_LogReporter.c
+ logging/parc_LogReporterFile.c
+ logging/parc_LogReporterTextStdout.c
+ logging/parc_LogFormatText.c
+ logging/parc_LogFormatSyslog.c
+ )
+
+set(LIBPARC_DEVELOPER_HEADER_FILES
+ developer/parc_TimingIntel.h
+ developer/parc_Stopwatch.h
+ developer/parc_Timing.h
+ )
+
+set(LIBPARC_DEVELOPER_SOURCE_FILES
+ developer/parc_TimingIntel.c
+ developer/parc_Stopwatch.c
+ )
+
+set(LIBPARC_STATISTICS_HEADER_FILES
+ statistics/parc_BasicStats.h
+ statistics/parc_EWMA.h
+ )
+
+set(LIBPARC_STATISTICS_SOURCE_FILES
+ statistics/parc_BasicStats.c
+ statistics/parc_EWMA.c
+ )
+
+set(LIBPARC_MEMORY_HEADER_FILES
+ memory/parc_BufferPool.h
+)
+
+set(LIBPARC_MEMORY_SOURCE_FILES
+ memory/parc_BufferPool.c
+)
+
+set(LIBPARC_SOURCE_FILES
+ ${LIBPARC_ALGOL_SOURCE_FILES}
+ ${LIBPARC_CONCURRENT_SOURCE_FILES}
+ ${LIBPARC_SECURITY_SOURCE_FILES}
+ ${LIBPARC_TESTING_SOURCE_FILES}
+ ${LIBPARC_LOGGING_SOURCE_FILES}
+ ${LIBPARC_DEVELOPER_SOURCE_FILES}
+ ${LIBPARC_BASE_HEADER_FILES}
+ ${LIBPARC_ALGOL_HEADER_FILES}
+ ${LIBPARC_PRIVATE_HEADER_FILES}
+ ${LIBPARC_TESTING_HEADER_FILES}
+ ${LIBPARC_SECURITY_HEADER_FILES}
+ ${LIBPARC_CONCURRENT_HEADER_FILES}
+ ${LIBPARC_CONCURRENT_SOURCE_FILES}
+ ${LIBPARC_LOGGING_HEADER_FILES}
+ ${LIBPARC_DEVELOPER_HEADER_FILES}
+ ${LIBPARC_STATISTICS_HEADER_FILES} ${LIBPARC_STATISTICS_SOURCE_FILES}
+ ${LIBPARC_MEMORY_HEADER_FILES} ${LIBPARC_MEMORY_SOURCE_FILES}
+ )
+
+set(LIBPARC_ALGOL_FILES ${LIBPARC_ALGOL_SOURCE_FILES} ${LIBPARC_ALGOL_HEADER_FILES})
+list(SORT LIBPARC_ALGOL_FILES)
+source_group(algol FILES ${LIBPARC_ALGOL_FILES})
+
+#source_group(algol FILES ${LIBPARC_ALGOL_SOURCE_FILES} ${LIBPARC_ALGOL_HEADER_FILES})
+source_group(concurrent FILES ${LIBPARC_CONCURRENT_SOURCE_FILES} ${LIBPARC_CONCURRENT_HEADER_FILES})
+source_group(security FILES ${LIBPARC_SECURITY_SOURCE_FILES} ${LIBPARC_SECURITY_HEADER_FILES})
+source_group(developer FILES ${LIBPARC_DEVELOPER_SOURCE_FILES} ${LIBPARC_DEVELOPER_HEADER_FILES})
+source_group(logging FILES ${LIBPARC_LOGGING_SOURCE_FILES} ${LIBPARC_LOGGING_HEADER_FILES})
+source_group(testing FILES ${LIBPARC_TESTING_SOURCE_FILES} ${LIBPARC_TESTING_HEADER_FILES})
+source_group(statistics FILES ${LIBPARC_STATISTICS_SOURCE_FILES} ${LIBPARC_STATISTICS_HEADER_FILES})
+source_group(memory FILES ${LIBPARC_MEMORY_SOURCE_FILES} ${LIBPARC_MEMORY_HEADER_FILES})
+
+if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang" OR COMPILE_FOR_IOS)
+ 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()
+if(COMPILE_FOR_IOS OR ANDROID_API)
+ add_library(parc STATIC ${LIBPARC_SOURCE_FILES} ${LIBEVENT_LIBRARIES} ${OPENSSL_LIBRARIES})
+ target_link_libraries(parc ${LIBEVENT_LIBRARIES})
+ target_link_libraries(parc ${OPENSSL_LIBRARIES})
+ set(libparcLibraries
+ parc
+ )
+else()
+ add_library(parc STATIC ${LIBPARC_SOURCE_FILES})
+ add_library(parc.shared SHARED ${LIBPARC_SOURCE_FILES})
+ target_link_libraries(parc.shared ${LIBEVENT_LIBRARIES})
+ target_link_libraries(parc.shared ${OPENSSL_LIBRARIES})
+ set_target_properties(parc.shared PROPERTIES
+ C_STANDARD 99
+ SOVERSION 1
+ VERSION 1.0
+ OUTPUT_NAME parc )
+ set(libparcLibraries
+ parc
+ parc.shared
+ )
+
+endif()
+
+
+foreach(lib ${libparcLibraries})
+ install(TARGETS ${lib} COMPONENT library LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
+ set_property(TARGET ${lib} PROPERTY C_STANDARD 99)
+endforeach()
+
+install(FILES ${LIBPARC_ALGOL_HEADER_FILES} DESTINATION include/parc/algol COMPONENT headers)
+install(FILES ${LIBPARC_SECURITY_HEADER_FILES} DESTINATION include/parc/security COMPONENT headers)
+install(FILES ${LIBPARC_LOGGING_HEADER_FILES} DESTINATION include/parc/logging COMPONENT headers)
+install(FILES ${LIBPARC_TESTING_HEADER_FILES} DESTINATION include/parc/testing COMPONENT headers)
+install(FILES ${LIBPARC_CONCURRENT_HEADER_FILES} DESTINATION include/parc/concurrent COMPONENT headers)
+install(FILES ${LIBPARC_DEVELOPER_HEADER_FILES} DESTINATION include/parc/developer COMPONENT headers)
+install(FILES ${LIBPARC_BASE_HEADER_FILES} DESTINATION include/parc COMPONENT headers)
+install(FILES ${LIBPARC_STATISTICS_HEADER_FILES} DESTINATION include/parc/statistics COMPONENT headers)
+install(FILES ${LIBPARC_MEMORY_HEADER_FILES} DESTINATION include/parc/memory COMPONENT headers)
+
+if(NOT COMPILE_FOR_IOS)
+ add_subdirectory(security/command-line)
+ add_subdirectory(algol/test)
+ add_subdirectory(concurrent/test)
+ add_subdirectory(developer/test)
+ add_subdirectory(security/test)
+ add_subdirectory(logging/test)
+ add_subdirectory(testing/test)
+ add_subdirectory(statistics/test)
+ add_subdirectory(memory/test)
+endif()
diff --git a/libparc/parc/HeaderDoc/Info.plist b/libparc/parc/HeaderDoc/Info.plist
new file mode 100644
index 00000000..63ab1e47
--- /dev/null
+++ b/libparc/parc/HeaderDoc/Info.plist
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleName</key>
+ <string>PARC C Library</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.parc.csl.c-library</string>
+ <key>DocSetPublisherIdentifier</key>
+ <string>com.parc.csl</string>
+ <key>DocSetPublisherName</key>
+ <string>PARC</string>
+</dict>
+</plist>
diff --git a/libparc/parc/HeaderDoc/Nodes.xml b/libparc/parc/HeaderDoc/Nodes.xml
new file mode 100644
index 00000000..51158a52
--- /dev/null
+++ b/libparc/parc/HeaderDoc/Nodes.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Nodes.xml are used to create directory structure in XCode - Organizer - Documentation
+-->
+
+<DocSetNodes version="1.0">
+<TOC>
+ <Node>
+ <Name>PARC Library</Name>
+
+ <Subnodes>
+ <!-- Services Documents -->
+ <Node>
+ <Name>Algorithms</Name>
+ <Subnodes>
+ <Node type="folder">
+ <Name>PARC Algol</Name>
+ <Path>Resources/Documents/</Path>
+ <File>masterTOC.html</File>
+ </Node>
+
+ <!-- add more services here -->
+ </Subnodes>
+ </Node>
+ <!-- END Service Documents -->
+ </Subnodes>
+ </Node>
+</TOC>
+</DocSetNodes>
+
diff --git a/libparc/parc/HeaderDoc/adcstyle.css b/libparc/parc/HeaderDoc/adcstyle.css
new file mode 100644
index 00000000..92c380e5
--- /dev/null
+++ b/libparc/parc/HeaderDoc/adcstyle.css
@@ -0,0 +1,869 @@
+/*!Copyright © 2010 Apple Inc. All rights reserved. */
+.showInXcodeSC{
+ display: none;
+}
+
+body {
+ margin:0;
+ background-color:#888;
+ color:#000;
+ font:13px 'Lucida Grande',Geneva,Verdana,Arial,Helvetica,sans-serif;
+}
+
+th,td {
+ font : 90% 'Lucida Grande',Geneva,Verdana,Arial,Helvetica,sans-serif;
+}
+code,pre {
+ font-family:monaco,'Courier New',courier,monospace;
+ font-size:107%;
+}
+* html code{font-size:101%;
+}
+* html pre{font-size:101%;
+}
+h1 code,h2 code,h3 code,h4 code,th code,ol.faq li code{font-size:95%;
+ font-weight:normal;
+}
+h1{margin:0 0 15px 0;
+ padding:0;
+ font:bold 36px 'Myriad Apple','Lucida Grande',Geneva,Verdana,Arial,Helvetica,sans-serif;
+ color:#000;
+}
+h1 #pagehead{margin:0 0 5px 0;
+ padding:0;
+ font:bold 30px 'Myriad','Lucida Grande',Geneva,Verdana,Arial,Helvetica,sans-serif;
+ color:#000;
+}
+h1 #pageheadsub{margin:0 0 5px 0;
+ padding:0;
+ font:bold 18px 'Myriad','Lucida Grande',Geneva,Verdana,Arial,Helvetica,sans-serif;
+ color:#777;
+}
+h2{margin:0 0 5px 0;
+ padding:0;
+ font-size:16px;
+ color:#000;
+ border-bottom:0;
+}
+#header h2{margin:0;
+}
+.adclogo{margin-top:12px;
+}
+.searchbox{width:180px;
+}
+p+h2{margin:20px 0 5px 0;
+}
+ol+h2{margin:20px 0 5px 0;
+}
+ul+h2{margin:20px 0 5px 0;
+}
+h3{margin:0;
+ padding:0;
+ font-size:12px;
+ color:#000;
+}
+h3+table{margin:5px 0 0 0;
+}
+h4{margin:0;
+ padding:0;
+ font-size:12px;
+}
+h3+h4{margin:10px 0 0;
+}
+h6{margin:0;
+ padding:0;
+ font:normal 12px 'Lucida Grande',Geneva,Verdana,Arial,Helvetica,sans-serif;
+ color:#000;
+}
+p{margin:0 0 10px 0;
+ padding:0;
+ font:12px 'Lucida Grande',Geneva,Verdana,Arial,Helvetica,sans-serif;
+ color:#000;
+}
+cite{font-style:italic;
+}
+th{font-weight:bold;
+ text-align:left;
+ vertical-align:top;
+}
+form{margin:0;
+}
+button{margin:3px 0 10px 0;
+}
+ul{list-style:square outside;
+ margin:0 0 0 30px;
+ padding:0 0 1em 0;
+}
+li{margin-top:3px;
+}
+ul ul{margin-left:40px;
+}
+ul.compressed{margin-top:-10px;
+}
+ul.compressed li{margin-top:0;
+}
+ul.marketing{padding-left:0;
+ margin:0 0 16px 0;
+ list-style:none;
+}
+ul.marketing li{margin-top:0;
+ margin-left:0;
+ margin-bottom:2px;
+ font-size:10px;
+}
+ol{margin:0 0 10px 1.5em;
+ padding-left:1.5em;
+}
+ul.inline,ol.inline,p.inline{margin-top:-7px;
+}
+ul.inline ul,ul.inline ol,ol.inline ul,ol.inline ol{margin-top:0;
+}
+ol.faq li{font-weight:bold;
+}
+ol.steps li{font-weight:bold;
+}
+ul.nav{margin:8px 0 0;
+ padding:0;
+ list-style-type:none;
+}
+ul.nav li {
+ margin-top:4px;
+ padding-left:0;
+}
+ul.nobullet{list-style-type:none;
+ margin-left:0;
+ padding-left:0;
+}
+ul.nobullet li{margin:3px 0 5px;
+ padding-left:0;
+}
+.leftinline{margin:0 10px 5px 0;
+ float:left;
+}
+.rightinline{margin:0 0 5px 10px;
+ float:right;
+}
+.bumblebee{border-top:1px solid #919699;
+ border-left:1px solid #919699;
+ border-right:1px solid #919699;
+}
+.bumblebee td{padding:10px;
+ font-size:10px;
+}
+.bumblebee th{padding:6px 10px;
+ font-size:10px;
+}
+.bumblebee th a{color:#FFF;
+}
+.bumblebee th a:link {
+ color:#FFF;
+}
+.bumblebee th a:visited {
+ color:#FFF;
+}
+.bumblebee th a:hover {
+ color:#FFF;
+}
+.bumblebee th a:active {
+ color:#FFF;
+}
+.bumblebee th {
+ background:#7E91A4;
+ color:#FFF;
+}
+.bumblebee td {
+ border-bottom:1px solid #919699;
+ text-align:left;
+ vertical-align:top;
+}
+.bumblebeeblue {
+ background:#F0F5F9;
+}
+.bumblebeewhite {
+ background:#FFF;
+}
+.bumblebee .bumblebeeblue td.sortcolumn{background:#DCE5EE;
+}
+.bumblebee .bumblebeewhite td.sortcolumn{background:#F5F5F5;
+}
+.bumblebee th.sortcolumn{background:#345;
+}
+.bumblebeetop{border-top:1px solid #919699;
+ border-left:1px solid #919699;
+ border-right:1px solid #919699;
+ background:#E2E2E2;
+}
+.bumblebeetop td{padding:10px;
+}
+table.bumblebeetop select{width:230px;
+}
+.bumblebeetop td.display{border-left:1px solid #a1a5a9;
+}
+.bumblebeetop .pagenav td{padding:5px 10px;
+ font-size:10px;
+ border-top:1px solid #a1a5a9;
+}
+.bumblebee .pagenav td{padding:5px 10px;
+ font-size:10px;
+ background:#E2E2E2;
+}
+.bumblebee .pagenav td.rightcolumn{text-align:right;
+}
+td.middle,th.middle{vertical-align:middle;
+}
+td.top,th.top{vertical-align:top;
+}
+td.bottom,th.bottom{vertical-align:bottom;
+}
+td.center,th.center{text-align:center;
+}
+td.right,th.right{text-align:right;
+}
+.smalltable td p{font-size:11px;
+}
+.graybox{border-top:1px solid #919699;
+ border-left:1px solid #919699;
+ margin-bottom:10px;
+}
+.graybox th{padding:4px 8px 4px 8px;
+ background:#E2E2E2;
+ font-size:12px;
+ font-weight:bold;
+ border-bottom:1px solid #919699;
+ border-right:1px solid #919699;
+}
+.graybox td{padding:8px;
+ font-size:12px;
+ text-align:left;
+ vertical-align:top;
+ border-bottom:1px solid #919699;
+ border-right:1px solid #919699;
+}
+.graybox table td{border:none;
+ padding:0;
+ vertical-align:middle;
+}
+.marketingbox{width:100%;
+ border:1px solid #a1a5a9;
+}
+.marketingbox th{padding:4px 8px 4px 8px;
+ background:#C83808;
+ font-size:12px;
+ font-weight:bold;
+ color:#FFF;
+}
+.marketingbox td{padding:8px 8px 0 8px;
+ text-align:left;
+ vertical-align:top;
+}
+.documentationtable{border:none;
+}
+.documentationtable td{border-bottom:1px solid #919699;
+ text-align:left;
+ vertical-align:top;
+ padding:8px 0 5px 0;
+}
+.documentationtable p{margin-bottom:8px;
+}
+.documentationtable .bottom{border:0;
+}
+.businesstable{border:none;
+}
+.businesstable td{text-align:left;
+ font-size:10px;
+ vertical-align:top;
+ padding:5px 0 10px 0;
+}
+.documentationtable p{font-size:10px;
+}
+p.viewall{font-size:11px;
+ font-weight:bold;
+}
+p.viewlegacytech{font-size:11px;
+}
+table.download{border:1px solid #919699;
+ margin-bottom:10px;
+}
+table.download th{padding:6px 10px 6px 10px;
+ font-size:10px;
+ background:#7E91A4;
+ color:#FFF;
+}
+table.download td{font-size:12px;
+ text-align:left;
+ vertical-align:top;
+}
+table.download .title td{border-top:1px solid #919699;
+ background:#F0F5F9;
+ padding:6px 10px 6px 10px;
+}
+table.download .title.sub td{border-top:none;
+}
+table.download .description{padding:10px;
+}
+table.download .title td.sortcolumn{background:#DCE5EE;
+}
+table.download .description td.sortcolumn{background:#F5F5F5;
+}
+table.download th.sortcolumn{background:#345;
+}
+table.download th a{color:#FFF;
+}
+table.downloadtop{border-top:1px solid #919699;
+ border-left:1px solid #919699;
+ border-right:1px solid #919699;
+ background:#E2E2E2;
+}
+table.downloadtop td{padding:10px 0 10px 10px;
+}
+.bigboxtop{background:#FFF url(/images/bigboxtop.gif) repeat-x top left;
+}
+.bigboxleft{background:#FFF url(/images/bigboxleft.gif) repeat-y top left;
+}
+.bigboxright{background:#FFF url(/images/bigboxright.gif) repeat-y top left;
+}
+.bigboxbottom{background:#FFF url(/images/bigboxbottom.gif) repeat-x top left;
+}
+.boxtop{background:#FFF url(/images/boxtop.gif) repeat-x top left;
+}
+.boxleft{background:#FFF url(/images/boxleft.gif) repeat-y top left;
+}
+.boxright{background:#FFF url(/images/boxright.gif) repeat-y top left;
+}
+.boxbottom{background:#FFF url(/images/boxbottom.gif) repeat-x top left;
+}
+.contentpadding{padding:0 10px;
+}
+.smalltext{font-size:10px;
+}
+.blueheader{color:#FFF;
+ background:#7E91A4;
+ padding:3px 0 3px 7px;
+}
+.sourcecodebox{border:1px solid #c7cfd5;
+ background:#f5f9fd;
+ margin:20px 0;
+ padding:8px;
+ text-align:left;
+}
+.notebox{border:1px solid #a1a5a9;
+ background:#f7f7f7;
+ margin:20px 0;
+ padding:8px;
+ text-align:left;
+}
+.importantbox{border:1px solid #111;
+ background:#e8e8e8;
+ margin:20px 0;
+ padding:8px;
+ text-align:left;
+}
+.warningbox{border:1px solid #000;
+ background:#fff;
+ margin:20px 0;
+ padding:8px;
+ text-align:left;
+}
+.warningbox img.warningicon{float:left;
+ margin-top:3px;
+}
+.warningbox p{margin:0 0 0 30px;
+}
+div.clearer{clear:both;
+ display:block;
+ margin:0;
+ padding:0;
+ height:0;
+ line-height:1px;
+ font-size:1px;
+}
+.gray{color:#787c7f;
+}
+#footnote h3,#footnote p{color:#76797C;
+ font-size:11px;
+}
+div.footnote{margin-top:30px;
+}
+.footnote,.footnote li,.footnote p,.footnote h3{font-size:11px;
+ color:#76797C;
+}
+.editorial{font-style:italic;
+ margin:20px 0;
+}
+.libindex{border-bottom:1px solid #939393;
+ padding:0 3px;
+ background-color:#DADADA;
+ margin:0 1px;
+}
+#forms input{vertical-align:middle;
+ padding:0;
+ margin:0 0 5px 0;
+}
+#forms select{vertical-align:middle;
+ padding:0;
+ margin:0 0 3px 0;
+}
+#forms .widefield,#advsearch .widefield{width:98%;
+ margin-bottom:5px;
+}
+#forms .halffield{width:50%;
+ margin-bottom:5px;
+}
+#forms .extraspace{padding-bottom:8px;
+}
+#forms .quarterfield{width:25%;
+ margin-bottom:5px;
+}
+#forms .inputbutton,#advsearch .inputbutton{margin:5px 0 10px 0;
+ border:0;
+}
+#forms .checkbox,#advsearch .checkbox{margin:0 5px 0 0;
+ vertical-align:baseline;
+}
+#forms .radio{margin:0 5px 0 0;
+ vertical-align:baseline;
+}
+#forms textarea{margin:0 0 10px 0;
+ width:100%;
+}
+#forms p{margin-top:7px;
+}
+#forms .buttonlists{line-height:20px;
+}
+#forms .buttondescription{line-height:15px;
+ margin:-10px 10px 5px 20px;
+ font-size:10px;
+}
+#adcnavheader td{font:10px 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif;
+}
+#adcnavheader input{margin:0 3px 0 0;
+ padding:0;
+}
+#adcnavheader .textpadding{padding-top:2px;
+ vertical-align:middle;
+}
+#adcnavheader .searchbutton{border:0;
+}
+#adcnavheader table.header{margin-top:13px;
+}
+#adcnavheader td.logo{height:65px;
+ padding:0;
+ text-align:left;
+}
+#adcnavheader td.search{height:35px;
+ text-align:right;
+}
+#adcnavheader td.adv-search{padding:0 4px 3px 0;
+}
+#adcnavheader td.restrict{padding:3px 0 0 0;
+}
+#breadcrumb td{font:10px 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif;
+}
+#breadcrumb form{margin:0;
+}
+#breadcrumb select{vertical-align:middle;
+}
+#sidebar h2,.swlsidebar h2{font-size:12px;
+}
+#sidebar h3,#sidebar h4,.swlsidebar h3,.swlsidebar h4{font-size:12px;
+}
+#sidebar p,#sidebar ol,#sidebar ul,.swlsidebar p,.swlsidebar ol,.swlsidebar ul{font-size:11px;
+}
+#sidebar ul,.swlsidebar ul{margin-left:16px;
+ padding-left:0;
+}
+#sidebar li,.swlsidebar li{font-size:11px;
+ margin-top:2px;
+}
+#sidebar ul.nav,.swlsidebar ul.nav{margin:8px 0 0;
+ padding:0;
+ list-style-type:none;
+}
+#sidebar ul.nav li,.swlsidebar ul.nav li{margin-top:4px;
+ padding-left:0;
+ background:none;
+}
+#footer td,#footer p{font-size:10px;
+}
+#footer{margin-top:24px;
+}
+.footerbreadcrumb{font-size:10px;
+}
+#notfound h2{font-size:12px;
+}
+#notfound h3,#notfound h4{font-size:12px;
+}
+#notfound p,#notfound ul{font-size:10px;
+}
+#notfound ul{margin:0 0 15px 0;
+ padding-left:0;
+ list-style-type:none;
+}
+#notfound ul li{font-size:10px;
+ margin:3px 0 0 0;
+ padding-left:0;
+ background:none;
+}
+#notfound ul ul{margin-top:0;
+ margin-left:16px;
+ list-style:square outside;
+}
+#notfound ul ul li{margin-left:0;
+ padding-left:0;
+}
+li.sectionbreak{margin-bottom:15px;
+}
+#advsearch h4{margin-bottom:10px;
+}
+#advsearch p{line-height:20px;
+}
+.iconlinks td{font-size:11px;
+}
+.boxtop7e91a4{background:#FFF url(/images/boxtop7e91a4.gif) repeat-x top left;
+}
+.boxtopleft7e91a4{background:#FFF url(/images/boxtopleft7e91a4.gif) repeat-y top left;
+}
+.boxtopright7e91a4{background:#FFF url(/images/boxtopright7e91a4.gif) repeat-y top left;
+}
+.boxbottom7e91a4{background:#FFF url(/images/boxbottom7e91a4.gif) repeat-x top left;
+}
+.filesize{color:#7F8285;
+}
+tr.results th,tr.results td{font-size:12px;
+ color:#FFF;
+ background-color:#7e91a4;
+ font-weight:normal;
+}
+tr.results a{color:#FFF;
+ font-weight:bold;
+}
+.oddrow{background-color:#fff;
+}
+.evenrow{background-color:#f0f5f9;
+}
+.swlleftrule{border-left:1px solid #A1A5A9;
+ padding-left:10px;
+ padding-right:10px;
+}
+.swlsidebar{padding-right:10px;
+}
+#narrative blockquote{margin:0 20px 10px 20px;
+ color:#3972B8;
+}
+#narrative .pullquote{font-size:17px;
+ color:#FFF;
+ padding:8px;
+ background-color:#3972B8;
+ border:1px solid #000;
+}
+#narrative.color779D90 blockquote{color:#779D90;
+}
+#narrative.color779D90 .pullquote{background-color:#779D90;
+}
+#narrative.color3C6E6E blockquote{color:#3C6E6E;
+}
+#narrative.color3C6E6E .pullquote{background-color:#3C6E6E;
+}
+#narrative.color6D8042 blockquote{color:#6D8042;
+}
+#narrative.color6D8042 .pullquote{background-color:#6D8042;
+}
+#narrative.color3E583D blockquote{color:#3E583D;
+}
+#narrative.color3E583D .pullquote{background-color:#3E583D;
+}
+#narrative.color9AB0C5 blockquote{color:#9AB0C5;
+}
+#narrative.color9AB0C5 .pullquote{background-color:#9AB0C5;
+}
+#narrative.color3972B8 blockquote{color:#3972B8;
+}
+#narrative.color3972B8 .pullquote{background-color:#3972B8;
+}
+#narrative.color3C6C9D blockquote{color:#3C6C9D;
+}
+#narrative.color3C6C9D .pullquote{background-color:#3C6C9D;
+}
+#narrative.color7A6B94 blockquote{color:#7A6B94;
+}
+#narrative.color7A6B94 .pullquote{background-color:#7A6B94;
+}
+#narrative.color50395C blockquote{color:#50395C;
+}
+#narrative.color50395C .pullquote{background-color:#50395C;
+}
+#narrative.color812A28 blockquote{color:#812A28;
+}
+#narrative.color812A28 .pullquote{background-color:#812A28;
+}
+#scdetails p{line-height:17px;
+}
+#scdetails select{vertical-align:middle;
+ padding:0;
+ margin:0;
+}
+#scdetails input{vertical-align:middle;
+ padding:0;
+ margin:0;
+}
+#techstart{float:right;
+ width:125px;
+ font-size:10px;
+ line-height:15px;
+ padding:8px 10px;
+ margin:0 0 5px 10px;
+ border:1px solid #a1a5a9;
+ background-color:#f1f1f1;
+}
+#techstart h3{font-size:12px;
+ margin-bottom:3px;
+}
+#techlist{font-size:11px;
+ margin:0 0 15px;
+}
+#techlist h2{position:relative;
+ font-size:12px;
+ padding:0 0 9px 35px;
+ margin:20px 0 5px;
+ background:url(/images/bg_tech_h2.gif) repeat-x bottom left;
+}
+#techlist h2 img{position:absolute;
+ left:0;
+ bottom:1%;
+}
+/* hack for various IEs \*/ #techlist img{bottom:0;
+}
+* html #techlist h2{height:100%;
+}
+/* end hack */ #techlist p,#techlist h3,#techlist li{font-size:11px;
+}
+#techlist ul.inlinebottom{padding-bottom:0;
+}
+#techlist h4{font-weight:bold;
+ color:#000;
+ font-size:11px;
+}
+#techchild h2{padding-bottom:5px;
+ border-bottom:1px solid #a1a5a9;
+ margin-bottom:10px;
+}
+#techchild h3{font-weight:normal;
+}
+#tigerbox{background:url(/images/tigerbox_bg_bottom.gif) no-repeat bottom;
+ border:1px solid #76797C;
+ padding:0;
+ margin-top:25px;
+}
+#tigerbox h3{background:url(/images/tigerbox_bg_top.gif) no-repeat top;
+ padding:10px 10px 25px 55px;
+}
+#tigerbox p{font-size:10px;
+ margin:0 12px 10px;
+}
+#tigerbox ul li{font-size:10px;
+ margin-left:5px;
+}
+#tigerbox h4{font-size:10px;
+ margin:0 12px;
+}
+.sidebartable{border:1px solid #a1a5a9;
+ margin-bottom:10px;
+}
+.sidebartable th{padding:4px 8px 4px 10px;
+ background:#DBDBDB;
+ font-size:12px;
+ font-weight:bold;
+ border-bottom:1px solid #a1a5a9;
+}
+.sidebartable td{padding:0 10px 10px;
+ font-size:11px;
+ text-align:left;
+ vertical-align:top;
+}
+.sidebartable h2,.sidebartable p,.sidebartable ul{margin:10px 0 2px;
+ padding:0;
+}
+.sidebartable table td{border:none;
+ padding:0;
+ vertical-align:middle;
+}
+h3.nolist{margin-bottom:5px;
+}
+#trfooter{border-top:1px solid #a1a5a9;
+ margin:28px auto -22px;
+ width:680px;
+ padding-top:5px;
+}
+#trfooter h3{display:inline;
+ vertical-align:top;
+}
+#trfooter ul{display:inline;
+ list-style:none outside;
+ margin:0;
+ padding:0;
+}
+#trfooter li{display:inline;
+ padding:0 5px;
+}
+.red{color:red;
+}
+.legacybox{border:2px solid #695D54;
+ background:#FFFACD;
+ margin-top:8px;
+ margin-right:10px;
+ padding:2px 5px 2px 8px;
+ text-align:left;
+}
+.legacybox p{font:12px lucida grande,geneva,helvetica,arial,sans-serif;
+ margin-top:2px;
+}
+.legacybox h1{font:14px lucida grande,geneva,helvetica,arial,sans-serif;
+ font-weight:bold;
+ text-align:center;
+ margin-top:5px;
+ margin-bottom:8px;
+}
+.closebutton{height:30px;
+ width:30px;
+ background:transparent url('../Images/book_ui_sprites@2x.png') 0 -20px;
+ background-size:110px;
+ float:right;
+}
+
+#tocMenu {
+ .background: #d5d5d5;
+ .color: black;
+}
+
+#howDoI h1{margin-top:.5em;
+ margin-bottom:1.15em;
+ font:215% 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif;
+ font-weight:normal;
+ color:#000;
+}
+#howDoI h2{margin-top:1.75em;
+ font-size:170%;
+ font-weight:normal;
+ color:#3c4c6c;
+ padding-bottom:2px;
+ border-bottom:1px solid #5088c5;
+}
+#howDoI h3{margin-top:1.5em;
+ margin-bottom:.25em;
+ font-size:130%;
+ font-weight:normal;
+ color:#000;
+}
+#howDoI p+h3{margin-top:25px;
+ margin-bottom:5px;
+ padding:0;
+ font-size:110%;
+ color:#000;
+}
+#howDoI .QA{margin-left:30px;
+ margin-bottom:30px;
+}
+#howDoI .caption{margin-top:20px;
+ margin-bottom:-10px;
+}
+#howDoI .graybox{border-top:0 solid #919699;
+ border-left:0 solid #919699;
+ margin-top:1em;
+ margin-bottom:4em;
+}
+#howDoI .graybox th{padding:.333em .667em .333em .667em;
+ background:#93A5BB;
+ font-size:90%;
+ font-weight:normal;
+ color:#fff;
+ border-bottom:0 solid #919699;
+ border-right:0 solid #919699;
+}
+#howDoI .graybox td{padding:.667em;
+ font-size:80%;
+ vertical-align:middle;
+ border-bottom:1px solid #80a3ca;
+ border-right:0 solid #919699;
+}
+#howDoI .graybox table td{border:none;
+ padding:0;
+ vertical-align:middle;
+}
+#howDoI ul.faq{list-style:none;
+ padding-top:.45em;
+ border-top:1px solid #d6e0e5;
+ border-bottom:1px solid #d6e0e5;
+ margin-top:0;
+ padding:0 0 6px 0;
+ font-size:90%;
+}
+#howDoI li{margin-top:3px;
+ font-weight:bold;
+ margin-bottom:3px;
+ padding-left:1.5em;
+ padding-right:.5em;
+ font-size:100%;
+}
+#howDoI ul.faq ul{list-style:none;
+ font-size:100% margin-top:5px;
+ margin-left:25px;
+ border-top:0 solid #d6e0e5;
+ border-bottom:0 solid #d6e0e5;
+}
+#howDoI ul.faq ul li{margin-top:6px;
+ font-weight:normal;
+}
+#howDoI ul{list-style:disc outside;
+ margin:0 0 0 20px;
+ padding:0 0 8px 0;
+}
+#howDoI ul.compressed{margin-top:-10px;
+}
+#howDoI ul.compressed li{margin-top:0;
+}
+#howDoI ul.marketing{padding-left:0;
+ margin:0 0 16px 0;
+ list-style:none;
+}
+#howDoI ul.marketing li{margin-top:0;
+ margin-left:0;
+ margin-bottom:2px;
+ font-size:10px;
+}
+#howDoI ol{margin:0 0 10px 1.5em;
+ padding-left:1.5em;
+}
+#howDoI ul.inline,ol.inline,p.inline{margin-top:-7px;
+}
+#howDoI ul.inline ul,ul.inline ol,ol.inline ul,ol.inline ol{margin-top:0;
+}
+#howDoI ol.faq li{font-weight:bold;
+}
+#howDoI ol.steps li{font-weight:bold;
+}
+#howDoI ul.nav{margin:8px 0 0;
+ padding:0;
+ list-style-type:none;
+}
+#howDoI ul.nav li{margin-top:4px;
+ padding-left:0;
+}
+#howDoI ul.nobullet{list-style-type:none;
+ margin-left:0;
+ padding-left:0;
+}
+#howDoI ul.nobullet li{margin:3px 0 5px;
+ padding-left:0;
+}
+#howDoI code,pre{font-size:12px;
+ font-family:Courier,monospace;
+ color:#666;
+}
+#howDoI .sourcecodebox{font-family:Courier,Consolas,monospace;
+ font-size:110%;
+ line-height:110%;
+ color:#666;
+}
+#howDoI p{font-size:92%;
+ line-height:150%;
+}
diff --git a/libparc/parc/HeaderDoc/gen_parc_docset.sh b/libparc/parc/HeaderDoc/gen_parc_docset.sh
new file mode 100644
index 00000000..3a4dbbd4
--- /dev/null
+++ b/libparc/parc/HeaderDoc/gen_parc_docset.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SETTING
+# location of XCODE docset
+DOCSET_DIR=../Docset/com.parc.csl.parc.docset
+
+# location of html code document, generated by headerdoc2html
+DOCUMENT_DIR=$DOCSET_DIR/Contents/Resources/Documents
+
+# location of hautelook templates, Info.plist Nodes.xml
+DOCSET_TEMPLATE_DIR=./
+
+# location of our source code, where headerdoc2html will spider through
+SOURCE_DIR=../algol/
+
+# clear screen
+clear
+
+# delete old docset and start from fresh, this will kill XCODE if its running. good for development only, comment out for production.
+rm -rf $DOCSET_DIR
+
+# create document directory
+mkdir -p $DOCUMENT_DIR
+
+# generate html code document for source code. -j will recognize java comment tag ex. /** */
+# https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/HeaderDoc/usage/usage.html#//apple_ref/doc/uid/TP40001215-CH337-SW2
+headerdoc2html --config-file headerDoc2HTML.config --class-as-composite -j -o $DOCUMENT_DIR $SOURCE_DIR
+#headerdoc2html -j -o $DOCUMENT_DIR $SOURCE_DIR/*.h
+
+# generate main index file. -d will generate Tokens.xml for us.
+#
+# http://opensource.apple.com/source/headerdoc/
+# https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/HeaderDoc/usage/usage.html#//apple_ref/doc/uid/TP40001215-CH337-SW1
+#
+gatherheaderdoc -d $DOCUMENT_DIR
+
+# copy required template files for apple docset
+cp $DOCSET_TEMPLATE_DIR/Info.plist $DOCSET_DIR/Contents/
+cp $DOCSET_TEMPLATE_DIR/Nodes.xml $DOCSET_DIR/Contents/Resources/
+cp $DOCUMENT_DIR/Tokens.xml $DOCSET_DIR/Contents/Resources/
+
+# create and validate apple docset indexes
+/Applications/Xcode.app/Contents/Developer/usr/bin/docsetutil index -verbose -debug $DOCSET_DIR
+/Applications/Xcode.app/Contents/Developer/usr/bin/docsetutil validate -verbose -debug $DOCSET_DIR
+
diff --git a/libparc/parc/HeaderDoc/headerDoc2HTML.config b/libparc/parc/HeaderDoc/headerDoc2HTML.config
new file mode 100644
index 00000000..97f740c2
--- /dev/null
+++ b/libparc/parc/HeaderDoc/headerDoc2HTML.config
@@ -0,0 +1,26 @@
+# Configuration file for HeaderDoc
+# $Revision: 1.11 $
+###########################################################
+# These options set various parameters used in content generation.
+copyrightOwner => Copyright (c) 2017 Cisco and/or its affiliates.
+defaultFrameName => index.html
+masterTOCName => masterTOC.html
+
+# To include information at the top or bottom of every page,
+# either include a string in htmlHeader/htmlFooter or a filename
+# in htmlHeaderFile or htmlFooterFile
+htmlHeader =>
+htmlHeaderFile =>
+htmlFooter =>
+htmlFooterFile =>
+
+# Tells HeaderDoc to suppress the default <style> content in a couple of places.
+#suppressDefaultStyles => 1
+
+# You can include additional stylesheet bits with any of the following:
+styleSheetExtrasFile => parcstyle.css
+# externalStyleSheets => /Resources/CSS/adcstyle.css
+# externalTOCStyleSheets => /Resources/CSS/frameset_styles.css
+# styleImports => @import "/Resources/CSS/frameset_styles.css";
+# tocStyleImports => @import "/Resources/CSS/frameset_styles.css";
+#tocStyleImports => @import "/Resources/CSS/adcstyle.css";
diff --git a/libparc/parc/HeaderDoc/parcstyle.css b/libparc/parc/HeaderDoc/parcstyle.css
new file mode 100644
index 00000000..e20199ef
--- /dev/null
+++ b/libparc/parc/HeaderDoc/parcstyle.css
@@ -0,0 +1,12 @@
+/* begin PARC style */
+.showInXcodeSC{
+ display: none;
+}
+
+body {
+ margin: 0;
+ background-color: #d5d5d5;
+ color: black;
+ font: medium 'Lucida Grande',Geneva,Verdana,Arial,Helvetica,sans-serif;
+}
+/* end PARC style */
diff --git a/libparc/parc/algol/.gitignore b/libparc/parc/algol/.gitignore
new file mode 100644
index 00000000..cf23441d
--- /dev/null
+++ b/libparc/parc/algol/.gitignore
@@ -0,0 +1,4 @@
+parcAlgol_About.c
+parcLibrary_About.c
+parcLibrary_About.h
+parcLibrary
diff --git a/libparc/parc/algol/Groups.dox b/libparc/parc/algol/Groups.dox
new file mode 100644
index 00000000..f798378c
--- /dev/null
+++ b/libparc/parc/algol/Groups.dox
@@ -0,0 +1,41 @@
+/**
+\mainpage
+The PARC Library is a collection of data structures, algorithms,
+abstractions and generally useful facilities for C programs.
+
+The most notable facility of the PARC library is the use of `PARCObject`
+reference counted allocated memory.
+
+The general abstractions provided by the library try to follow along with the
+Java runtime.
+For example, the PARC Library provides `PARCHashMap`, `PARCLinkedList`,
+`PARCInputStream`, and so forth.
+Ideally, the Java programmer will feel at home with the PARC Library.
+
+@defgroup types Basic Types
+@brief Basic Types
+
+@defgroup object Reference counted object types
+@brief Reference counted object types
+
+@defgroup datastructures Data Structures
+@brief Data structures
+
+@defgroup inputoutput Input Output
+@brief Functions to manage input and output.
+
+@defgroup memory Memory and Buffer Management
+@brief Functions to manage memory and references to memory.
+
+@defgroup threading Threading and Concurrency
+@brief Functions to manage Threading and Concurrency.
+
+@defgroup security Security
+@brief Functions to manage Security.
+
+@defgroup developer Developer Aids
+@brief Functions to provide Developer Aids.
+
+@defgroup networking Networking and Communication
+@brief Functions to manage Networking and Communication.
+*/
diff --git a/libparc/parc/algol/internal_parc_Event.c b/libparc/parc/algol/internal_parc_Event.c
new file mode 100755
index 00000000..74e917bf
--- /dev/null
+++ b/libparc/parc/algol/internal_parc_Event.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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_Memory.h>
+#include "internal_parc_Event.h"
+
+/**
+ * Current implementation based on top of libevent2
+ */
+#include <event2/event.h>
+#include <event2/bufferevent.h>
+
+void *
+internal_parc_alloc(size_t size)
+{
+ void *pointer;
+
+ pointer = parcMemory_AllocateAndClear(size);
+ return pointer;
+}
+
+void *
+internal_parc_realloc(void *pointer, size_t newSize)
+{
+ void *newPointer;
+ newPointer = parcMemory_Reallocate(pointer, newSize);
+ return newPointer;
+}
+
+// We interpose on the standard "free" interface to protect against freed memory accesses.
+void
+internal_parc_free(void *ptr)
+{
+ parcMemory_Deallocate((void **) &ptr);
+}
+
+static int _libeventInitialized = 0;
+
+void
+internal_parc_initializeLibevent(void)
+{
+ if (_libeventInitialized) {
+ return;
+ }
+ _libeventInitialized = 1;
+
+ // 0x AA BB CC XX
+ // AA = major
+ // BB = minor
+ // CC = patchlevel
+ //
+ uint32_t version = event_get_version_number();
+ trapIllegalValueIf(version < 0x02001000UL,
+ "Libevent version must be at least 2.0.16, got %s",
+ event_get_version());
+
+ // Make sure libevent uses our memory allocator.
+ // Libevent allocates an internal object the first time a base is allocated
+ // that it never releases. In order to ensure our outstanding memory counters
+ // start at zero we trigger this allocation before interposing our memory allocator.
+ //
+ // Create a scheduler event base, an event, then free both of them.
+ //
+ struct event_base *evbase = event_base_new();
+ assertNotNull(evbase, "Libevent event_base_new returned NULL");
+ struct event *event = event_new(evbase, -1, 0, NULL, NULL);
+ assertNotNull(event, "Libevent event_new returned NULL");
+ event_del(event);
+ event_base_free(evbase);
+ event_free(event);
+
+ event_set_mem_functions(internal_parc_alloc,
+ internal_parc_realloc,
+ internal_parc_free);
+}
+
+PARCEventPriority
+internal_libevent_priority_to_PARCEventPriority(short evpriority)
+{
+ PARCEventPriority priority = 0;
+ switch (evpriority) {
+ case 0: priority = PARCEventPriority_Maximum;
+ break;
+ case 1: priority = PARCEventPriority_Normal;
+ break;
+ case 2: priority = PARCEventPriority_Minimum;
+ break;
+ default:
+ assertTrue(0, "Unknown Libevent priority 0x%x\n", evpriority);
+ break;
+ }
+ return priority;
+}
+
+short
+internal_PARCEventPriority_to_libevent_priority(PARCEventPriority priority)
+{
+ short evpriority = 0;
+ switch (priority) {
+ case PARCEventPriority_Maximum: evpriority = 0;
+ break;
+ case PARCEventPriority_Normal: evpriority = 1;
+ break;
+ case PARCEventPriority_Minimum: evpriority = 2;
+ break;
+ default:
+ assertTrue(0, "Unknown PARCEventPriority 0x%x\n", evpriority);
+ break;
+ }
+ return evpriority;
+}
+
+PARCEventSchedulerDispatchType
+internal_eventloop_options_to_PARCEventSchedulerDispatchType(short evoptions)
+{
+ PARCEventSchedulerDispatchType options = 0;
+ switch (evoptions) {
+ case 0: options = PARCEventSchedulerDispatchType_Blocking;
+ break;
+ case EVLOOP_ONCE: options = PARCEventSchedulerDispatchType_LoopOnce;
+ break;
+ case EVLOOP_NONBLOCK: options = PARCEventSchedulerDispatchType_NonBlocking;
+ break;
+ default:
+ assertTrue(0, "Unknown Libevent dispatcher flag 0x%x\n", evoptions);
+ break;
+ }
+ return options;
+}
+
+short
+internal_PARCEventSchedulerDispatchType_to_eventloop_options(PARCEventSchedulerDispatchType options)
+{
+ short evoptions = 0;
+ switch (options) {
+ case PARCEventSchedulerDispatchType_Blocking: evoptions = 0;
+ break;
+ case PARCEventSchedulerDispatchType_LoopOnce: evoptions = EVLOOP_ONCE;
+ break;
+ case PARCEventSchedulerDispatchType_NonBlocking: evoptions = EVLOOP_NONBLOCK;
+ break;
+ default:
+ assertTrue(0, "Unknown PARCEventSchedulerDispatchType option 0x%x\n", evoptions);
+ break;
+ }
+ return evoptions;
+}
+
+PARCEventQueueOption
+internal_bufferevent_options_to_PARCEventQueueOption(short evflags)
+{
+ PARCEventQueueOption flags = 0;
+ if (evflags & BEV_OPT_CLOSE_ON_FREE) {
+ flags |= PARCEventQueueOption_CloseOnFree;
+ evflags &= ~BEV_OPT_CLOSE_ON_FREE;
+ }
+ if (evflags & BEV_OPT_DEFER_CALLBACKS) {
+ flags |= PARCEventQueueOption_DeferCallbacks;
+ evflags &= ~BEV_OPT_DEFER_CALLBACKS;
+ }
+ assertTrue(evflags == 0, "Unknown Libevent option flag 0x%x\n", evflags);
+ return flags;
+}
+
+short
+internal_PARCEventQueueOption_to_bufferevent_options(PARCEventQueueOption flags)
+{
+ short evflags = 0;
+ if (flags & PARCEventQueueOption_CloseOnFree) {
+ evflags |= BEV_OPT_CLOSE_ON_FREE;
+ flags &= ~PARCEventQueueOption_CloseOnFree;
+ }
+ if (flags & PARCEventQueueOption_DeferCallbacks) {
+ evflags |= BEV_OPT_DEFER_CALLBACKS;
+ flags &= ~PARCEventQueueOption_DeferCallbacks;
+ }
+ assertTrue(flags == 0, "Unknown PARCEventQueueOption flag 0x%x\n", flags);
+ return evflags;
+}
+
+PARCEventQueueEventType
+internal_bufferevent_type_to_PARCEventQueueEventType(short evtypes)
+{
+ PARCEventQueueEventType types = 0;
+ if (evtypes & BEV_EVENT_READING) {
+ types |= PARCEventQueueEventType_Reading;
+ evtypes &= ~BEV_EVENT_READING;
+ }
+ if (evtypes & BEV_EVENT_WRITING) {
+ types |= PARCEventQueueEventType_Writing;
+ evtypes &= ~BEV_EVENT_WRITING;
+ }
+ if (evtypes & BEV_EVENT_EOF) {
+ types |= PARCEventQueueEventType_EOF;
+ evtypes &= ~BEV_EVENT_EOF;
+ }
+ if (evtypes & BEV_EVENT_ERROR) {
+ types |= PARCEventQueueEventType_Error;
+ evtypes &= ~BEV_EVENT_ERROR;
+ }
+ if (evtypes & BEV_EVENT_TIMEOUT) {
+ types |= PARCEventQueueEventType_Timeout;
+ evtypes &= ~BEV_EVENT_TIMEOUT;
+ }
+ if (evtypes & BEV_EVENT_CONNECTED) {
+ types |= PARCEventQueueEventType_Connected;
+ evtypes &= ~BEV_EVENT_CONNECTED;
+ }
+ assertTrue(evtypes == 0, "Unknown Libevent type flag 0x%x\n", evtypes);
+ return types;
+}
+
+short
+internal_PARCEventQueueEventType_to_bufferevent_type(PARCEventQueueEventType types)
+{
+ short evtypes = 0;
+ if (types & PARCEventQueueEventType_Reading) {
+ evtypes |= BEV_EVENT_READING;
+ types &= ~PARCEventQueueEventType_Reading;
+ }
+ if (types & PARCEventQueueEventType_Writing) {
+ evtypes |= BEV_EVENT_WRITING;
+ types &= ~PARCEventQueueEventType_Writing;
+ }
+ if (types & PARCEventQueueEventType_EOF) {
+ evtypes |= BEV_EVENT_EOF;
+ types &= ~PARCEventQueueEventType_EOF;
+ }
+ if (types & PARCEventQueueEventType_Error) {
+ evtypes |= BEV_EVENT_ERROR;
+ types &= ~PARCEventQueueEventType_Error;
+ }
+ if (types & PARCEventQueueEventType_Timeout) {
+ evtypes |= BEV_EVENT_TIMEOUT;
+ types &= ~PARCEventQueueEventType_Timeout;
+ }
+ if (types & PARCEventQueueEventType_Connected) {
+ evtypes |= BEV_EVENT_CONNECTED;
+ types &= ~PARCEventQueueEventType_Connected;
+ }
+ assertTrue(types == 0, "Unknown PARCEventQueueEventType 0x%x\n", types);
+ return evtypes;
+}
+
+PARCEventType
+internal_libevent_type_to_PARCEventType(short evtypes)
+{
+ PARCEventType types = 0;
+ if (evtypes & EV_TIMEOUT) {
+ types |= PARCEventType_Timeout;
+ evtypes &= ~EV_TIMEOUT;
+ }
+ if (evtypes & EV_READ) {
+ types |= PARCEventType_Read;
+ evtypes &= ~EV_READ;
+ }
+ if (evtypes & EV_WRITE) {
+ types |= PARCEventType_Write;
+ evtypes &= ~EV_WRITE;
+ }
+ if (evtypes & EV_SIGNAL) {
+ types |= PARCEventType_Signal;
+ evtypes &= ~EV_SIGNAL;
+ }
+ if (evtypes & EV_PERSIST) {
+ types |= PARCEventType_Persist;
+ evtypes &= ~EV_PERSIST;
+ }
+ if (evtypes & EV_ET) {
+ types |= PARCEventType_EdgeTriggered;
+ evtypes &= ~EV_ET;
+ }
+ assertTrue(evtypes == 0, "Unknown Libevent event type 0x%x\n", evtypes);
+ return types;
+}
+
+short
+internal_PARCEventType_to_libevent_type(PARCEventType types)
+{
+ short evtypes = 0;
+ if (types & PARCEventType_Timeout) {
+ evtypes |= EV_TIMEOUT;
+ types &= ~PARCEventType_Timeout;
+ }
+ if (types & PARCEventType_Read) {
+ evtypes |= EV_READ;
+ types &= ~PARCEventType_Read;
+ }
+ if (types & PARCEventType_Write) {
+ evtypes |= EV_WRITE;
+ types &= ~PARCEventType_Write;
+ }
+ if (types & PARCEventType_Signal) {
+ evtypes |= EV_SIGNAL;
+ types &= ~PARCEventType_Signal;
+ }
+ if (types & PARCEventType_Persist) {
+ evtypes |= EV_PERSIST;
+ types &= ~PARCEventType_Persist;
+ }
+ if (types & PARCEventType_EdgeTriggered) {
+ evtypes |= EV_ET;
+ types &= ~PARCEventType_EdgeTriggered;
+ }
+ assertTrue(types == 0, "Unknown Libevent event type 0x%x\n", types);
+ return evtypes;
+}
diff --git a/libparc/parc/algol/internal_parc_Event.h b/libparc/parc/algol/internal_parc_Event.h
new file mode 100755
index 00000000..ab157a56
--- /dev/null
+++ b/libparc/parc/algol/internal_parc_Event.h
@@ -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.
+ */
+
+/**
+ * @file parc_EventQueue.h
+ * @ingroup events
+ * @brief Queue buffer events
+ *
+ * Provides a facade implementing many regularly available event functions.
+ * This is an interface that software implementors may use to substitute
+ * different kinds of underlying implementations of these event management functions.
+ * Notable examples are libevent and libev.
+ *
+ */
+#ifndef libparc_internal_parc_Event_h
+#define libparc_internal_parc_Event_h
+
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_EventQueue.h>
+
+/**
+ * Map alloc() method call to a PARC internal memory method
+ *
+ * @param [in] size of memory to allocate
+ * @returns NULL on error, memory pointer on success.
+ *
+ * Example:
+ * @code
+ * {
+ * return internal_parc_alloc(1024);
+ * }
+ * @endcode
+ *
+ */
+void *internal_parc_alloc(size_t size);
+
+/**
+ * Map realloc() method call to a PARC internal memory method
+ *
+ * @param [in] pointer to memory to reallocate
+ * @param [in] newSize of memory to allocate
+ * @returns NULL on error, new memory pointer on success.
+ *
+ * Example:
+ * @code
+ * {
+ * return internal_parc_realloc(ptr, 2048);
+ * }
+ * @endcode
+ *
+ */
+void *internal_parc_realloc(void *pointer, size_t newSize);
+
+/**
+ * Map free() method call to a PARC internal memory method
+ *
+ * @param [in] pointer to memory to free
+ *
+ * Example:
+ * @code
+ * {
+ * internal_parc_free(ptr);
+ * }
+ * @endcode
+ *
+ */
+void internal_parc_free(void *ptr);
+
+/**
+ * Verify and initialize libevent
+ *
+ * Example:
+ * @code
+ * {
+ * internal_parc_initializeLibevent();
+ * }
+ * @endcode
+ *
+ */
+void internal_parc_initializeLibevent(void);
+
+/**
+ * Convert from/to libevent dispatcher options and PARCEventSchedulerDispatcherType options.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventSchedulerDispatchType type = internal_eventloop_options_to_PARCEventSchedulerDispatchType(EVLOOP_ONCE);
+ * short evtype = internal_PARCEventSchedulerDispatchType_to_eventloop_options(PARCEventSchedulerDispatchType_LoopOnce);
+ * }
+ * @endcode
+ *
+ */
+PARCEventSchedulerDispatchType internal_eventloop_options_to_PARCEventSchedulerDispatchType(short evoptions);
+short internal_PARCEventSchedulerDispatchType_to_eventloop_options(PARCEventSchedulerDispatchType options);
+
+/**
+ * Convert from/to libevent bufferevent options and PARCEventQueueOption.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventQueueOption parcEventQueueOption = internal_bufferevent_options_to_PARCEventQueueOption(BEV_OPT_CLOSE_ON_FREE);
+ * short buffereventOption = internal_PARCEventQueueOption_to_bufferevent_options(PARCEventQueueOption_CloseOnFree);
+ * }
+ * @endcode
+ *
+ */
+PARCEventQueueOption internal_bufferevent_options_to_PARCEventQueueOption(short evflags);
+short internal_PARCEventQueueOption_to_bufferevent_options(PARCEventQueueOption flags);
+
+/**
+ * Convert from/to libevent bufferevent types and PARCEventQueueEventType.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventQueueEventType parcEventQueueEventType = internal_bufferevent_type_to_PARCEventQueueEventType(BEV_EVENT_READING);
+ * short buffereventOptions = internal_PARCEventQueueEventType_to_bufferevent_type(PARCEventQueueEventType_Reading);
+ * }
+ * @endcode
+ *
+ */
+PARCEventQueueEventType internal_bufferevent_type_to_PARCEventQueueEventType(short evtypes);
+short internal_PARCEventQueueEventType_to_bufferevent_type(PARCEventQueueEventType types);
+
+/**
+ * Convert from/to libevent event types and PARCEventType.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventType parcEventType = internal_libevent_type_to_PARCEventType(EV_READ);
+ * short buffereventOptions = internal_PARCEventType_to_libevent_type(PARCEventType_Read);
+ * }
+ * @endcode
+ *
+ */
+PARCEventType internal_libevent_type_to_PARCEventType(short evtypes);
+short internal_PARCEventType_to_libevent_type(PARCEventType types);
+
+/**
+ * Convert from/to libevent priority types and PARCEventPriority.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventPriority parcEventPriority = internal_libevent_priority_to_PARCEventPriority(0);
+ * short priority = internal_PARCEventPriority_to_libevent_priority(PARCEventPriority_Normal);
+ * }
+ * @endcode
+ *
+ */
+short internal_PARCEventPriority_to_libevent_priority(PARCEventPriority priority);
+PARCEventPriority internal_libevent_priority_to_PARCEventPriority(short evpriority);
+#endif // libparc_internal_parc_Event_h
diff --git a/libparc/parc/algol/parc_ArrayList.c b/libparc/parc/algol/parc_ArrayList.c
new file mode 100644
index 00000000..e9597070
--- /dev/null
+++ b/libparc/parc/algol/parc_ArrayList.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 <config.h>
+
+#include <stdio.h>
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+PARCListInterface *PARCArrayListAsPARCList = &(PARCListInterface) {
+ .Add = (bool (*)(void *, void *))parcArrayList_Add,
+ .AddAtIndex = (void (*)(void *, int index, void *))parcArrayList_InsertAtIndex,
+ .AddCollection = (bool (*)(void *, PARCCollection *))NULL,
+ .AddCollectionAtIndex = (bool (*)(void *, int index, PARCCollection *))NULL,
+ .Clear = (void (*)(void *))parcArrayList_Clear,
+ .Contains = (bool (*)(const void *, const PARCObject *))NULL,
+ .ContainsCollection = (bool (*)(const void *, const PARCCollection *))NULL,
+ .Copy = (void * (*)(const PARCList *))parcArrayList_Copy,
+ .Destroy = (void (*)(void **))parcArrayList_Destroy,
+ .Equals = (bool (*)(const void *, const void *))parcArrayList_Equals,
+ .GetAtIndex = (void * (*)(const void *, size_t))parcArrayList_Get,
+ .HashCode = (PARCHashCode (*)(const void *))NULL,
+ .IndexOf = (size_t (*)(const void *, const PARCObject *element))NULL,
+ .IsEmpty = (bool (*)(const void *))parcArrayList_IsEmpty,
+ .LastIndexOf = (size_t (*)(void *, const PARCObject *element))NULL,
+ .Remove = (bool (*)(void *, const PARCObject *))NULL,
+ .RemoveAtIndex = (void * (*)(PARCList *, size_t))parcArrayList_RemoveAtIndex,
+ .RemoveCollection = (bool (*)(void *, const PARCCollection *))NULL,
+ .RetainCollection = (bool (*)(void *, const PARCCollection *))NULL,
+ .SetAtIndex = (void * (*)(void *, size_t index, void *))parcArrayList_Set,
+ .Size = (size_t (*)(const void *))parcArrayList_Size,
+ .SubList = (PARCList * (*)(const void *, size_t, size_t))NULL,
+ .ToArray = (void** (*)(const void *))NULL,
+};
+
+struct parc_array_list {
+ void **array;
+ size_t numberOfElements;
+ size_t limit;
+ bool (*equalsElement)(void *x, void *y);
+ void (*destroyElement)(void **elementAddress);
+};
+
+static size_t
+_remaining(const PARCArrayList *array)
+{
+ return array->limit - array->numberOfElements;
+}
+
+static PARCArrayList *
+_ensureCapacity(PARCArrayList *array, size_t newCapacity)
+{
+ void *newArray = parcMemory_Reallocate(array->array, newCapacity * sizeof(void *));
+
+ if (newArray == NULL) {
+ return NULL;
+ }
+ array->array = newArray;
+ array->limit = newCapacity;
+
+ return array;
+}
+
+static PARCArrayList *
+_ensureRemaining(PARCArrayList *array, size_t remnant)
+{
+ assertNotNull(array, "Parameter must be a non-null PARCArrayList pointer.");
+
+ if (_remaining(array) < remnant) {
+ size_t newCapacity = parcArrayList_Size(array) + remnant;
+ return _ensureCapacity(array, newCapacity);
+ }
+ return array;
+}
+
+bool
+parcArrayList_IsValid(const PARCArrayList *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ if (instance->numberOfElements == 0 ? true : instance->array != NULL) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+void
+parcArrayList_AssertValid(const PARCArrayList *instance)
+{
+ trapIllegalValueIf(instance == NULL, "Parameter must be a non-null PARC_ArrayList pointer.");
+ assertTrue(instance->numberOfElements == 0 ? true : instance->array != NULL, "PARC_ArrayList size is inconsistent.");
+}
+
+static PARCArrayList *
+_parcArrayList_Init(PARCArrayList *arrayList,
+ size_t nElements,
+ size_t limit,
+ void **array,
+ bool (*equalsElement)(void *x, void *y),
+ void (*destroyElement)(void **elementAddress))
+{
+ if (arrayList != NULL) {
+ arrayList->array = array;
+ arrayList->numberOfElements = nElements;
+ arrayList->limit = limit;
+ arrayList->equalsElement = equalsElement;
+ arrayList->destroyElement = destroyElement;
+ }
+ return arrayList;
+}
+
+PARCArrayList *
+parcArrayList_Create(void (*destroyElement)(void **element))
+{
+ PARCArrayList *result = parcMemory_AllocateAndClear(sizeof(PARCArrayList));
+ assertNotNull(result, "Memory allocation of PARCArrayList failed");
+
+ return _parcArrayList_Init(result, 0, 0, NULL, NULL, destroyElement);
+}
+
+PARCArrayList *
+parcArrayList_Create_Capacity(bool (*equalsElement)(void *x, void *y), void (*destroyElement)(void **element), size_t size)
+{
+ PARCArrayList *result = parcMemory_AllocateAndClear(sizeof(PARCArrayList));
+ assertNotNull(result, "Memory allocation of PARCArrayList failed");
+
+ _parcArrayList_Init(result, 0, 0, NULL, equalsElement, destroyElement);
+
+ if (result != NULL) {
+ _ensureRemaining(result, size);
+ }
+
+ return result;
+}
+
+bool
+parcArrayList_Add(PARCArrayList *array, const void *pointer)
+{
+ parcArrayList_OptionalAssertValid(array);
+
+ if (_ensureRemaining(array, 1) == NULL) {
+ trapOutOfMemory("Cannot increase space for PARCArrayList.");
+ }
+ array->array[array->numberOfElements++] = (void *) pointer;
+
+ return true;
+}
+
+PARCArrayList *
+parcArrayList_AddAll(PARCArrayList *array, void *argv[], size_t argc)
+{
+ for (size_t i = 0; i < argc; i++) {
+ parcArrayList_Add(array, argv[i]);
+ }
+
+ return array;
+}
+
+bool
+parcArrayList_IsEmpty(const PARCArrayList *list)
+{
+ parcArrayList_OptionalAssertValid(list);
+
+ return list->numberOfElements == 0;
+}
+
+bool
+parcArrayList_Equals(const PARCArrayList *a, const PARCArrayList *b)
+{
+ bool result = true;
+
+ if (a != b) {
+ if (a == NULL || b == NULL) {
+ result = false;
+ } else if (a->numberOfElements != b->numberOfElements) {
+ result = false;
+ } else {
+ for (size_t i = 0; i < a->numberOfElements; i++) {
+ if (a->equalsElement != NULL) {
+ if (!a->equalsElement(a->array[i], b->array[i])) {
+ result = false;
+ break;
+ }
+ } else {
+ if (a->array[i] != b->array[i]) {
+ result = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+void *
+parcArrayList_RemoveAtIndex(PARCArrayList *array, size_t index)
+{
+ trapOutOfBoundsIf(index >= array->numberOfElements, "Index must be within the range [0, %zu)", array->numberOfElements);
+
+ void *element = array->array[index];
+
+ // Adjust the list to elide the element.
+ for (size_t i = index; i < array->numberOfElements - 1; i++) {
+ array->array[i] = array->array[i + 1];
+ }
+ array->numberOfElements--;
+
+ return element;
+}
+
+void
+parcArrayList_Set(const PARCArrayList *array, size_t index, void *pointer)
+{
+ trapOutOfBoundsIf(index >= array->numberOfElements, "Index must be within the range [0, %zu)", array->numberOfElements);
+
+ array->array[index] = pointer;
+}
+
+void *
+parcArrayList_Get(const PARCArrayList *array, size_t index)
+{
+ trapOutOfBoundsIf(index >= array->numberOfElements, "Index must be within the range [0, %zu)", array->numberOfElements);
+
+ return array->array[index];
+}
+
+void *
+parcArrayList_Peek(const PARCArrayList *list)
+{
+ return parcArrayList_Get(list, parcArrayList_Size(list) - 1);
+}
+
+size_t
+parcArrayList_Size(const PARCArrayList *pointerArray)
+{
+ return pointerArray->numberOfElements;
+}
+
+void
+parcArrayList_Destroy(PARCArrayList **arrayPtr)
+{
+ assertNotNull(arrayPtr, "Parameter must be a non-null pointer to a PARC_ArrayList pointer.");
+
+ PARCArrayList *array = *arrayPtr;
+
+ parcArrayList_OptionalAssertValid(array);
+
+ assertTrue(array->numberOfElements == 0 ? true : array->array != NULL, "PARC_ArrayList is inconsistent.");
+
+ if (array->destroyElement != NULL) {
+ for (size_t i = 0; i < array->numberOfElements; i++) {
+ if (array->array[i] != NULL) {
+ array->destroyElement(&array->array[i]);
+ }
+ }
+ }
+
+ if (array->array != NULL) {
+ parcMemory_Deallocate((void **) &(array->array));
+ }
+
+ parcMemory_Deallocate((void **) &array);
+ *arrayPtr = 0;
+}
+
+PARCArrayList *
+parcArrayList_Copy(const PARCArrayList *original)
+{
+ parcArrayList_OptionalAssertValid(original);
+
+ PARCArrayList *result = parcArrayList_Create(original->destroyElement);
+
+ if (result != NULL) {
+ for (size_t i = 0; i < original->numberOfElements; i++) {
+ parcArrayList_Add(result, original->array[i]);
+ }
+ }
+
+ return result;
+}
+
+void
+parcArrayList_StdlibFreeFunction(void **elementPtr)
+{
+ if (elementPtr != NULL) {
+ free(*elementPtr);
+ *elementPtr = 0;
+ }
+}
+
+void
+parcArrayList_PARCMemoryFreeFunction(void **elementPtr)
+{
+ if (elementPtr != NULL) {
+ parcMemory_Deallocate((void **) elementPtr);
+ *elementPtr = 0;
+ }
+}
+
+PARCArrayList *
+parcArrayList_RemoveAndDestroyAtIndex(PARCArrayList *array, size_t index)
+{
+ parcArrayList_OptionalAssertValid(array);
+
+ assertTrue(index < array->numberOfElements, "Index must be ( 0 <= index < %zd). Actual=%zd", array->numberOfElements, index);
+
+ if (index < array->numberOfElements) {
+ // Destroy the element at the given index.
+ if (array->destroyElement != NULL) {
+ array->destroyElement(&array->array[index]);
+ }
+
+ // Adjust the list to elide the element.
+ for (size_t i = index; i < array->numberOfElements - 1; i++) {
+ array->array[i] = array->array[i + 1];
+ }
+ array->numberOfElements--;
+ }
+
+ return array;
+}
+
+PARCArrayList *
+parcArrayList_InsertAtIndex(PARCArrayList *array, size_t index, const void *pointer)
+{
+ parcArrayList_OptionalAssertValid(array);
+ size_t length = parcArrayList_Size(array);
+
+ assertTrue(index <= array->numberOfElements, "You can't insert beyond the end of the list");
+
+ // Create space and grow the array if needed
+ _ensureRemaining(array, length + 1);
+ for (size_t i = index; i < length; i++) {
+ array->array[i + 1] = array->array[i];
+ }
+ array->numberOfElements++;
+
+ array->array[index] = (void *) pointer;
+
+ return array;
+}
+
+void *
+parcArrayList_Pop(PARCArrayList *array)
+{
+ return parcArrayList_RemoveAtIndex(array, parcArrayList_Size(array) - 1);
+}
+
+void
+parcArrayList_Clear(PARCArrayList *array)
+{
+ while (!parcArrayList_IsEmpty(array)) {
+ parcArrayList_RemoveAndDestroyAtIndex(array, parcArrayList_Size(array) - 1);
+ }
+}
diff --git a/libparc/parc/algol/parc_ArrayList.h b/libparc/parc/algol/parc_ArrayList.h
new file mode 100644
index 00000000..1e2be6b0
--- /dev/null
+++ b/libparc/parc/algol/parc_ArrayList.h
@@ -0,0 +1,577 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_ArrayList.h
+ * @ingroup datastructures
+ * @brief A dynamic array of void * pointers.
+ *
+ * This module implements a dynamic array of simple void pointers.
+ * Users can create an empty array, or preprovisioned with an initial capacity of N elements.
+ *
+ */
+#ifndef libparc_parc_ArrayList_h
+#define libparc_parc_ArrayList_h
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Iterator.h>
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcArrayList_OptionalAssertValid(_instance_)
+#else
+# define parcArrayList_OptionalAssertValid(_instance_) parcArrayList_AssertValid(_instance_)
+#endif
+
+struct parc_array_list;
+typedef struct parc_array_list PARCArrayList;
+
+/**
+ * The mapping of a `PARCArrayList` to the generic `PARCList`.
+ */
+extern PARCListInterface *PARCArrayListAsPARCList;
+
+/**
+ * Determine if a `PARCArrayList` is valid.
+ *
+ * @param [in] instance A pointer to a PARCArrayList instance.
+ *
+ * @return true The instance is valid.
+ * @return true The instance is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *list = parcArrayList_Create(NULL);
+ * if (parcArrayList_IsValid(list)) {
+ * printf("The list is valid.");
+ * }
+ * parcArrayList_Destroy((list);
+ * @endcode
+ */
+bool parcArrayList_IsValid(const PARCArrayList *instance);
+
+/**
+ * Assert that a `PARCArrayList` is valid.
+ *
+ * @param [in] instance A pointer to a PARCArrayList instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *list = parcArrayList_Create(NULL);
+ *
+ * parcArrayList_AssertValid(list);
+ *
+ * parcArrayList_Destroy((list);
+ * @endcode
+ */
+void parcArrayList_AssertValid(const PARCArrayList *instance);
+
+/**
+ * Add an element to the given PARCArrayList.
+ *
+ * If the PARCArrayList was constructed with a destroyer,
+ * the pointer will be destroyed when element is removed or the list is destroyed.
+ *
+ * @param [in] array A pointer to a `PARCArrayList`.
+ * @param [in] pointer A void pointer to the item to be added to the list.
+ *
+ * @return True If the value was successfully added to the list.
+ * @return False Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * void *elements[] = {
+ * strdup("a"),
+ * strdup("b"),
+ * strdup("c"),
+ * };
+ *
+ * bool wasAdded = parcArrayList_Add(array, elements);
+ * printf("Successfully added the base pointer? %d\n", wasAdded);
+ *
+ * ...
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+bool parcArrayList_Add(PARCArrayList *array, const void *pointer);
+
+/**
+ * Add all of the pointers in the given array of pointers to the `PARCArrayList`.
+ *
+ * This is synonymous with calling {@link parcArrayList_Add()} multiple times
+ *
+ * @param [in] array A pointer to `PARCArrayList`.
+ * @param [in] argv A pointer to the base list of pointers.
+ * @param [in] argc The number of items to add to the list, starting from the abse void pointer.
+ *
+ * @return A pointer to the modified PARCArrayList.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * void *elements[] = {
+ * strdup("a"),
+ * strdup("b"),
+ * strdup("c"),
+ * };
+ *
+ * parcArrayList_AddAll(array, elements, 3);
+ *
+ * ...
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+PARCArrayList *parcArrayList_AddAll(PARCArrayList *array, void **argv, size_t argc);
+
+/**
+ * Remove an element at a specific index from a `PARCArrayList`.
+ *
+ * The element is destroyed via the function provided when calling {@link parcArrayList_Create()}.
+ * The index must be 0 <= index < length.
+ *
+ * @param [in,out] array A pointer to `PARCArrayList`.
+ * @param [in] index The index of the element to remove and destroy.
+ *
+ * @return A pointer to the modified `PARCArrayList`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * void *elements[] = {
+ * strdup("a"),
+ * strdup("b"),
+ * strdup("c"),
+ * };
+ *
+ * parcArrayList_AddAll(array, elements, 3);
+ * parcArrayList_RemoveAndDestroyAtIndex(array, 0);
+ *
+ * size_t size = parcArrayList_Size(array);
+ * // size will now be three
+ *
+ * ...
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+PARCArrayList *parcArrayList_RemoveAndDestroyAtIndex(PARCArrayList *array, size_t index);
+
+/**
+ * Return the element at index. Remove the element from the array.
+ *
+ * The index must be 0 <= index < length.
+ *
+ * @param [in,out] array A pointer to a `PARCArrayList` instance.
+ * @param [in] index The index of the element to remove.
+ *
+ * @return void* A pointer (void *) to the element that was removed.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * void *elements[] = {
+ * strdup("a"),
+ * strdup("b"),
+ * strdup("c"),
+ * };
+ *
+ * parcArrayList_AddAll(array, elements, 3);
+ * void *firstString = parcArrayList_RemoveAtIndex(array, 0);
+ *
+ * printf("First string: %s\n", firstString);
+ *
+ * ...
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+void *parcArrayList_RemoveAtIndex(PARCArrayList *array, size_t index);
+
+/**
+ * Insert an element at the index location. Elements will be moved up if required.
+ *
+ * You may not insert beyond the list end. (You can insert at the end, but not any more).
+ *
+ * @param [in,out] array A `PARCArrayList`
+ * @param [in] pointer A pointer to the element to insert
+ * @param [in] index An index in the `PARCArrayList`
+ * @return A pointer to the modified `PARCArrayList`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ *
+ * parcArrayList_InsertAtIndex(array, strdup("a"), 0);
+ * void *firstString = parcArrayList_RemoveAtIndex(array, 0);
+ * printf("First string is 'a': %s\n", firstString);
+ *
+ * ...
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+PARCArrayList *parcArrayList_InsertAtIndex(PARCArrayList *array, size_t index, const void *pointer);
+
+/**
+ * Create an instance of an empty `PARCArrayList`.
+ *
+ * @param [in] destroyElement
+ * A pointer to a function that will destroy (or equivalent) the element pointed to by `element`
+ *
+ * @return A pointer to the new `PARCArrayList` instance, or NULL if no memory could be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * ...
+ * }
+ * @endcode
+ */
+PARCArrayList *parcArrayList_Create(void (*destroyElement)(void **elementAddress));
+
+/**
+ * Create an instance of a PARCArrayList pre-provisioned to contain the specified number of elements.
+ *
+ * @param [in] equalsElement
+ * A pointer to a function that will determine equality between two elements in the array.
+ * @param [in] destroyElement
+ * A pointer to a function that will destroy (or equivalent) the element pointed to by <code>element</code>
+ * @param [in] size
+ * The number of initial elements to provision for.
+ * @return A pointer to a new `PARCArrayList` instance, or NULL if no memory could be allocated.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCArrayList *parcArrayList_Create_Capacity(bool (*equalsElement)(void *x, void *y), void (*destroyElement)(void **elementAddress), size_t size);
+
+/**
+ * Copy a `PARCArrayList` instance.
+ *
+ * Create a new `PARCArrayList` instance with the same structure and content as the original.
+ *
+ * @param [in] array A pointer to a `PARCArrayList` instance to copy.
+ *
+ * @return A pointer to a new `PARCArrayList` instance with a copy of the original, or NULL if no memory could be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * parcArrayList_InsertAtIndex(array, strdup("a"), 0);
+ *
+ * PARCArrayList *sameList = parcArrayList_Copy(array);
+ *
+ * if (parcArrayList_Equals(array, sameList)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+PARCArrayList *parcArrayList_Copy(const PARCArrayList *array);
+
+/**
+ * Destroy a `PARCArrayList` instance.
+ *
+ * Destroy the given `PARCArrayList` by freeing all memory used by it.
+ *
+ * @param [in,out] arrayPtr A pointer to the pointer of the `PARCArrayList` to be destroyed.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ *
+ * ...
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+void parcArrayList_Destroy(PARCArrayList **arrayPtr);
+
+/**
+ * Set an element from the given `PARCArrayList` at a specified index to a value.
+ *
+ * The index must be 0 <= index < length.
+ *
+ * @param [in] array A pointer to a `PARCArrayList` instance.
+ * @param [in] index The index into the `PARCArrayList` instance.
+ * @param [in] pointer A void pointer to the item to be assigned to the index
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * void *elements[] = {
+ * strdup("a"),
+ * strdup("b"),
+ * strdup("c"),
+ * };
+ *
+ * bool wasAdded = parcArrayList_Add(array, elements);
+ * // how to free the pointer at index 1 without deallocating the slot? XXX
+ * parcArrayList_Set(array, 1, strdup("d");
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+void parcArrayList_Set(const PARCArrayList *array, size_t index, void *pointer);
+
+/**
+ * Get an element from the given `PARCArrayList` at a specified index.
+ *
+ * The index must be 0 <= index < length.
+ *
+ * @param [in] array A pointer to a `PARCArrayList` instance.
+ * @param [in] index The index into the `PARCArrayList` instance.
+ *
+ * @return A pointer (void *) to the element in the list.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * void *elements[] = {
+ * strdup("a"),
+ * strdup("b"),
+ * strdup("c"),
+ * };
+ *
+ * parcArrayList_AddAll(array, elements, 3);
+ * void *firstString = parcArrayList_Get(array, 0);
+ *
+ * printf("First string: %s\n", firstString);
+ *
+ * ...
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+void *parcArrayList_Get(const PARCArrayList *array, size_t index);
+
+/**
+ * Return the number of elements in the given `PARCArrayList`.
+ *
+ * The size is the number of elements, NOT the size in bytes of all elements maintained in the list.
+ *
+ * @param [in] array A pointer to a `PARCArrayList` instance.
+ *
+ * @return A size_t of the number of elements in the given `PARCArrayList`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ * void *elements[] = {
+ * strdup("a"),
+ * strdup("b"),
+ * strdup("c"),
+ * };
+ *
+ * parcArrayList_AddAll(array, elements, 3);
+ *
+ * size_t size = parcArrayList_Size(array);
+ * printf("Size =?= 3: %d\n", size == 3);
+ *
+ * parcArrayList_Destroy(&array);
+ * }
+ * @endcode
+ */
+size_t parcArrayList_Size(const PARCArrayList *array);
+
+/**
+ * Determine if two `PARCArrayList` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCArrayList` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, parcArrayList_Equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, parcArrayList_Equals(x, y) must return true if and only if
+ * parcArrayList_Equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * parcArrayList_Equals(x, y) returns true and
+ * parcArrayList_Equals(y, z) returns true,
+ * then parcArrayList_Equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of parcArrayList_Equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, parcArrayList_Equals(x, NULL)) must return false.
+ *
+ * @param [in] a The first `PARCArrayList` instance.
+ * @param [in] b The second `PARCArrayList` instance.
+ *
+ * @return true the given PARCArrayList instances are equal.
+ * @return false the given PARCArrayList instances are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCArrayList *a = parcArrayList_Create();
+ * PARCArrayList *b = parcArrayList_Create();
+ *
+ * if (parcArrayList_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool parcArrayList_Equals(const PARCArrayList *a, const PARCArrayList *b);
+
+/**
+ * Standard library free(3) wrapper for use as a destructor function for elements of a `PARCArrayList`.
+ *
+ * The create functions for `PARCArrayList` have an input parameter that is a pointer to a function that
+ * will be called for each element when the `PARCArrayList` is destroyed, and when an element is removed via
+ * {@link parcArrayList_RemoveAndDestroyAtIndex}.
+ * This destroy function has a different calling signature than the standard library's free(3) function.
+ * This function is a wrapper providing the correct facade for the standard library free(3) function.
+ *
+ * @param [in,out] element A pointer to the element to be destroyed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcArrayList_StdlibFreeFunction(void **element);
+
+/**
+ * PARC_Memory free() wrapper for use as a destructor function for elements of a `PARCArrayList`.
+ *
+ * The create functions for `PARCArrayList` have an input parameter that is a pointer to a function that
+ * will be called for each element when the `PARCArrayList` is destroyed, and when an element is removed via
+ * {@link parcArrayList_RemoveAndDestroyAtIndex}.
+ * This destroy function has a different calling signature than the PARC_Memory's free(3) function.
+ * This function is a wrapper providing the correct facade for the PARC_Memory's free(3) function.
+ *
+ * @param [in,out] elementPtr A pointer to the element to be destroyed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcArrayList_PARCMemoryFreeFunction(void **elementPtr);
+
+/**
+ * Tests if this list is empty.
+ *
+ *
+ * @param [in] list A pointer to the `PARCArrayList` to test.
+ * @return true if the stack is empty.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcArrayList_IsEmpty(const PARCArrayList *list);
+
+/**
+ * Returns a pointer to object at the top of this stack without removing it from the stack.
+ *
+ * @param [in] list A pointer to `PARCArrayList`.
+ * @return A pointer to the first element of the `PARCArrayList`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcArrayList_Peek(const PARCArrayList *list);
+
+/**
+ * Removes the object at the top of this stack and returns that object as the value of this function.
+ *
+ * @param [in,out] list A pointer to the `PARCArrayList`.
+ * @return A pointer to what was the first element of the `PARCArrayList`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcArrayList_Pop(PARCArrayList *list);
+
+/**
+ * Removes all objects from this stack.
+ *
+ * @param [in,out] list A pointer to the `PARCArrayList`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcArrayList_Clear(PARCArrayList *list);
+
+/**
+ * Pushes an item onto the top of this stack.
+ *
+ * @param [in,out] list A pointer to a `PARCArrayList`.
+ * @param [in] item A pointer to an element to be added to the `PARCArrayList`.
+ * @return A pointer to the item just pushed on to the `PARCArrayLis.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcArrayList_Push(PARCArrayList *list, void *item);
+
+/**
+ * Returns the 1-based position where an object is on this stack.
+ *
+ * @param [in] list A pointer to `PARCArrayList`.
+ * @param [in] element A pointer to the element to locate in the `PARCArrayList`.
+ * @return int The index of the located element in the `PARCArrayList`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int parcArrayList_Search(PARCArrayList *list, void *element);
+#endif // libparc_parc_ArrayList_h
diff --git a/libparc/parc/algol/parc_AtomicInteger.c b/libparc/parc/algol/parc_AtomicInteger.c
new file mode 100755
index 00000000..b32a698f
--- /dev/null
+++ b/libparc/parc/algol/parc_AtomicInteger.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <parc/algol/parc_AtomicInteger.h>
+
+#ifdef USE_GCC_EXTENSIONS
+uint32_t
+parcAtomicInteger_Uint32IncrementGCC(uint32_t *value)
+{
+ return __sync_add_and_fetch(value, 1);
+}
+
+uint32_t
+parcAtomicInteger_Uint32DecrementGCC(uint32_t *value)
+{
+ return __sync_sub_and_fetch(value, 1);
+}
+
+uint64_t
+parcAtomicInteger_Uint64IncrementGCC(uint64_t *value)
+{
+ return __sync_add_and_fetch(value, 1);
+}
+
+uint64_t
+parcAtomicInteger_Uint64DecrementGCC(uint64_t *value)
+{
+ return __sync_sub_and_fetch(value, 1);
+}
+#endif
+
+
+// Since there is no per integer mutex, we must use something to protect an integer from multiple,
+// simultaneous competitors.
+// Unfortunately, this is an indiscrimiate mutex causing all atomic integer updates to be
+// serialized rather than each individually protected.
+static pthread_mutex_t _parcAtomicInteger_PthreadMutex = PTHREAD_MUTEX_INITIALIZER;
+
+uint32_t
+parcAtomicInteger_Uint32IncrementPthread(uint32_t *value)
+{
+ pthread_mutex_lock(&_parcAtomicInteger_PthreadMutex);
+ *value = *value + 1;
+ uint32_t result = *value;
+ pthread_mutex_unlock(&_parcAtomicInteger_PthreadMutex);
+ return result;
+}
+
+uint32_t
+parcAtomicInteger_Uint32DecrementPthread(uint32_t *value)
+{
+ pthread_mutex_lock(&_parcAtomicInteger_PthreadMutex);
+ *value = *value - 1;
+ uint32_t result = *value;
+ pthread_mutex_unlock(&_parcAtomicInteger_PthreadMutex);
+ return result;
+}
+
+uint64_t
+parcAtomicInteger_Uint64IncrementPthread(uint64_t *value)
+{
+ pthread_mutex_lock(&_parcAtomicInteger_PthreadMutex);
+ *value = *value + 1;
+ uint64_t result = *value;
+ pthread_mutex_unlock(&_parcAtomicInteger_PthreadMutex);
+ return result;
+}
+
+uint64_t
+parcAtomicInteger_Uint64DecrementPthread(uint64_t *value)
+{
+ pthread_mutex_lock(&_parcAtomicInteger_PthreadMutex);
+ *value = *value - 1;
+ uint64_t result = *value;
+ pthread_mutex_unlock(&_parcAtomicInteger_PthreadMutex);
+ return result;
+}
diff --git a/libparc/parc/algol/parc_AtomicInteger.h b/libparc/parc/algol/parc_AtomicInteger.h
new file mode 100755
index 00000000..729d9a01
--- /dev/null
+++ b/libparc/parc/algol/parc_AtomicInteger.h
@@ -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.
+ */
+
+/**
+ * @file parc_AtomicInteger.h
+ * @ingroup threading
+ * @brief An integer value that may be updated automatically.
+ *
+ */
+#ifndef libparc_parc_AtomicInteger_h
+#define libparc_parc_AtomicInteger_h
+
+#include <stdint.h>
+
+/*
+ * If we are compiling with GCC or Clang, then
+ * we have some compiler extensions to make use of processer
+ * compare-and-swap and other kinds of synchronisation primitives.
+ */
+#if defined(__GNUC__) || defined(__clang__)
+# define USE_GCC_EXTENSIONS 1
+#endif
+
+// Turn this off until the problem on the SMP machines is worked out, case 787.
+#undef USE_GCC_EXTENSIONS
+
+#ifdef USE_GCC_EXTENSIONS
+uint32_t parcAtomicInteger_Uint32IncrementGCC(uint32_t *value);
+
+uint32_t parcAtomicInteger_Uint32DecrementGCC(uint32_t *value);
+
+uint64_t parcAtomicInteger_Uint64IncrementGCC(uint64_t *value);
+
+uint64_t parcAtomicInteger_Uint64DecrementGCC(uint64_t *value);
+
+#define parcAtomicInteger_Uint32Increment parcAtomicInteger_Uint32IncrementGCC
+
+#define parcAtomicInteger_Uint32Decrement parcAtomicInteger_Uint32DecrementGCC
+
+#define parcAtomicInteger_Uint64Increment parcAtomicInteger_Uint64IncrementGCC
+
+#define parcAtomicInteger_Uint64Decrement parcAtomicInteger_Uint64DecrementGCC
+
+#else
+uint32_t parcAtomicInteger_Uint32IncrementPthread(uint32_t *value);
+
+uint32_t parcAtomicInteger_Uint32DecrementPthread(uint32_t *value);
+
+uint64_t parcAtomicInteger_Uint64IncrementPthread(uint64_t *value);
+
+uint64_t parcAtomicInteger_Uint64DecrementPthread(uint64_t *value);
+
+#define parcAtomicInteger_Uint32Increment parcAtomicInteger_Uint32IncrementPthread
+
+#define parcAtomicInteger_Uint32Decrement parcAtomicInteger_Uint32DecrementPthread
+
+#define parcAtomicInteger_Uint64Increment parcAtomicInteger_Uint64IncrementPthread
+
+#define parcAtomicInteger_Uint64Decrement parcAtomicInteger_Uint64DecrementPthread
+#endif
+#endif // libparc_parc_AtomicInteger_h
diff --git a/libparc/parc/algol/parc_Base64.c b/libparc/parc/algol/parc_Base64.c
new file mode 100755
index 00000000..38020479
--- /dev/null
+++ b/libparc/parc/algol/parc_Base64.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.
+ */
+
+/**
+ *
+ * Encode/decode base64. Encoding goes to one long line, no line breaks.
+ * Decoding will accept CRLF linebreaks in the data and skip them.
+ *
+ * Following the language of RFC 4648, encoding proceeds in a "quantum" of
+ * 3 bytes of plaintext to 4 bytes of encoded data. Decoding goes in
+ * a 4-byte quantum to 3-byte decoded data.
+ *
+ * If decoding fails (e.g. there's a non-base64 character), then the output
+ * buffer is rewound to the starting position and a failure is indicated.
+ *
+ * Decoding using a 256 byte table. Each byte of the 4-byte quantum is looked
+ * up and if its a valid character -- it resolves to a value 0..63, then that
+ * value is shifted to the right position in the output. Values CR and LF have
+ * the special token "_" in the table, which means "skip". That token has value
+ * ascii value 95, is we can detect it as outside base64. Similarly, all the
+ * invalid characters have the symbol "~", which is ascii 127.
+ *
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Base64.h>
+#include <parc/algol/parc_Memory.h>
+
+const uint8_t base64code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+const uint8_t pad = '=';
+
+const uint8_t invalid = '~'; // has ascii value 127, outside base64
+const uint8_t skip = '_'; // has ascii value 95, outside the base64 values
+
+// an 256-entry table to lookup decode values. If the value is "invalid", then it's not
+// a base64 character.
+const uint8_t decodeTable[256] = {
+/* 0 */ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '_', '~', '~', '_', '~', '~',
+/* 16 */ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
+/* 32 */ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', 62, '~', '~', '~', 63,
+/* 48 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, '~', '~', '~', '~', '~', '~',
+/* 64 */ '~', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+/* 80 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, '~', '~', '~', '~', '~',
+/* 96 */ '~', 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+/* 112 */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, '~', '~', '~', '~', '~',
+/* 128 */ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
+ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
+ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
+ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
+ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
+ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
+ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
+ '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~'
+};
+
+#define min(a, b) ((a < b) ? a : b)
+
+/**
+ * Encode the 3-byte quantum pointed to by <code>quantum</code> into 4 encoded characters.
+ * It includes `padLength` of pad necessary at the end.
+ */
+static void
+_encodeWithPad(PARCBufferComposer *output, const uint8_t *quantum, size_t padLength)
+{
+ assertTrue(padLength < 3, "Degenerate case -- should never pad all 3 bytes!");
+
+ unsigned index;
+
+ uint8_t paddedQuantum[] = { 0, 0, 0 };
+ memcpy(paddedQuantum, quantum, 3 - padLength);
+
+ for (index = 0; index < 4; index++) {
+ if (index + padLength < 4) {
+ /*
+ * The four base64 symbols fall in to these locations in the
+ * 3-byte input
+ *
+ * aaaaaabb | bbbbcccc | ccdddddd
+ *
+ * This switch statement, based on the "a" "b" "c" or "d" case
+ * extracts the corresponding 6 bits from its location in the
+ * byte aray.
+ */
+ int sixbit = 0;
+ switch (index) {
+ case 0: // aaaaaa
+ sixbit = paddedQuantum[0] >> 2;
+ break;
+
+ case 1: // bbbbbb
+ sixbit = ((paddedQuantum[0] & 0x03) << 4) | (paddedQuantum[1] >> 4);
+ break;
+
+ case 2: // cccccc
+ sixbit = ((paddedQuantum[1] & 0x0F) << 2) | (paddedQuantum[2] >> 6);
+ break;
+
+ case 3: // dddddd
+ sixbit = paddedQuantum[2] & 0x3F;
+ break;
+ }
+ uint8_t encodedChar = base64code[ sixbit ];
+ parcBufferComposer_PutUint8(output, encodedChar);
+ } else {
+ parcBufferComposer_PutUint8(output, pad);
+ }
+ }
+}
+
+/**
+ * Decode the 4-byte quantum of base64 to binary.
+ */
+static bool
+_decode(PARCBufferComposer *output, uint8_t *quantum)
+{
+ uint8_t threebytes[3] = { 0, 0, 0 };
+ size_t length_to_append = 0;
+
+ for (int index = 0; index < 4; index++) {
+ uint8_t c = quantum[index];
+ if (c != pad) {
+ uint8_t value = decodeTable[c];
+
+ // if its a non-base64 character, bail out of here
+ if (value == invalid) {
+ return false;
+ }
+
+ /*
+ * The four base64 symbols fall in to these locations in the
+ * final 3-byte output
+ *
+ * aaaaaabb | bbbbcccc | ccdddddd
+ */
+ switch (index) {
+ case 0: // aaaaaa
+ threebytes[0] |= value << 2;
+ break;
+
+ case 1: // bbbbbb
+ threebytes[0] |= (value & 0x30) >> 4;
+ threebytes[1] |= (value & 0x0F) << 4;
+
+ // we've finished threebytes[0]
+ length_to_append = 1;
+ break;
+
+ case 2: // cccccc
+ threebytes[1] |= value >> 2;
+ threebytes[2] |= (value & 0x03) << 6;
+
+ // we've finished threebytes[1]
+ length_to_append = 2;
+ break;
+
+ case 3: // dddddd
+ threebytes[2] |= value;
+
+ // we've finished threebytes[2]
+ length_to_append = 3;
+ break;
+ }
+ }
+ }
+
+ parcBufferComposer_PutArray(output, threebytes, length_to_append);
+ return true;
+}
+
+PARCBufferComposer *
+parcBase64_Encode(PARCBufferComposer *result, PARCBuffer *plainText)
+{
+ size_t remaining = parcBuffer_Remaining(plainText);
+ if (remaining > 0) {
+ const uint8_t *buffer = parcBuffer_Overlay(plainText, 0);
+ result = parcBase64_EncodeArray(result, remaining, buffer);
+ }
+
+ return result;
+}
+
+PARCBufferComposer *
+parcBase64_EncodeArray(PARCBufferComposer *output, size_t length, const uint8_t array[length])
+{
+ size_t offset = 0;
+
+ // Encode 3-byte tuples
+ while (offset < length) {
+ const uint8_t *quantum = array + offset;
+ size_t padLength = 3 - min(3, length - offset);
+ _encodeWithPad(output, quantum, padLength);
+ offset += 3;
+ }
+
+ return output;
+}
+
+PARCBufferComposer *
+parcBase64_Decode(PARCBufferComposer *output, PARCBuffer *encodedText)
+{
+ // We proceed in 4-byte blocks. All base-64 encoded data is a multiple of 4 bytes.
+ // If the length of encodedText is wrong, bail now
+
+ size_t remaining = parcBuffer_Remaining(encodedText);
+ const uint8_t *buffer = parcBuffer_Overlay(encodedText, remaining);
+ return parcBase64_DecodeArray(output, remaining, buffer);
+}
+
+PARCBufferComposer *
+parcBase64_DecodeString(PARCBufferComposer *output, const char *encodedString)
+{
+ const uint8_t *buffer = (const uint8_t *) encodedString;
+ size_t length = strlen(encodedString);
+ return parcBase64_DecodeArray(output, length, buffer);
+}
+
+PARCBufferComposer *
+parcBase64_DecodeArray(PARCBufferComposer *output, size_t length, const uint8_t array[length])
+{
+ size_t offset = 0;
+ bool success = true;
+
+ // if we need to rollback, this is where we go
+ PARCBuffer *outputBuffer = parcBufferComposer_GetBuffer(output);
+ size_t rewind_to = parcBuffer_Position(outputBuffer);
+
+ while (offset < length && success) {
+ // filter out line feeds and carrage returns
+ // parse the input in 4-byte quantums
+ size_t index = 0;
+ uint8_t quantum[4];
+
+ // reset success at the start of each loop. if we run out of input before
+ // we parse a full quantum, we'll fail the loop and rewind the output buffer.
+ success = false;
+
+ // 4 == quantum length for decode
+ while (index < 4 && offset < length) {
+ uint8_t c = array[offset];
+ uint8_t decoded = decodeTable[c];
+
+ if (decoded < 64 || c == pad) {
+ // this is an artifact from how the code was first written, so we
+ // pass the un-decoded character
+ quantum[index] = c;
+ index++;
+ offset++;
+ continue;
+ }
+
+ if (decoded == skip) {
+ offset++;
+ continue;
+ }
+
+ if (decoded == invalid) {
+ break;
+ }
+ }
+
+ if (index == 4) {
+ success = _decode(output, quantum);
+ }
+ }
+
+ if (!success) {
+ parcBuffer_SetPosition(outputBuffer, rewind_to);
+ return NULL;
+ }
+
+ return output;
+}
diff --git a/libparc/parc/algol/parc_Base64.h b/libparc/parc/algol/parc_Base64.h
new file mode 100644
index 00000000..7d60797a
--- /dev/null
+++ b/libparc/parc/algol/parc_Base64.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 parc_Base64.h
+ * @ingroup inputoutput
+ * @brief Encode/decode base64
+ *
+ * Encoding goes to one long line, no line breaks.
+ * Decoding will accept CRLF linebreaks in the data and skip them.
+ *
+ * Following the language of RFC 4648, encoding proceeds in a "quantum" of
+ * 3 bytes of plaintext to 4 bytes of encoded data. Decoding goes in
+ * a 4-byte quantum to 3-byte decoded data.
+ *
+ * If decoding fails (e.g. there's a non-base64 character), then the output
+ * buffer is rewound to the starting position and a failure is indicated.
+ *
+ * Decoding using a 256 byte table. Each byte of the 4-byte quantum is looked
+ * up and if its a valid character -- it resolves to a value 0..63, then that
+ * value is shifted to the right position in the output. Values CR and LF have
+ * the special token "_" in the table, which means "skip". That token has value
+ * ascii value 95, is we can detect it as outside base64. Similarly, all the
+ * invalid characters have the symbol "~", which is ascii 127.
+ *
+ */
+#ifndef libparc_parc_Base64_h
+#define libparc_parc_Base64_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+/**
+ * Encode the plaintext buffer to base64, as per RFC 4648, Section 4.
+ *
+ * The base64 encoding is appended to `output` at the current position, and `output` is returned.
+ *
+ * @param [in,out] output The instance of {@link PARCBufferComposer} to which the encoded @plainText is appended
+ * @param [in] plainText The text to encode and append to @p output
+ *
+ * @return A pointer to the @p output
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+PARCBufferComposer *parcBase64_Encode(PARCBufferComposer *output, PARCBuffer *plainText);
+
+/**
+ * Encode the array to base64.
+ *
+ * @param [in,out] output The instance of {@link PARCBufferComposer} to which the encoded @p array is appended
+ * @param [in] length The length of the Array to be encoded
+ * @param array The array to be encoded and appended to @p output
+ *
+ * @return A pointer to the @p output
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferComposer *parcBase64_EncodeArray(PARCBufferComposer *output, size_t length, const uint8_t *array);
+
+/**
+ * Base64 decode the @p encodedText and append the result to @p output,
+ * which is returned by the function.
+ *
+ * If the @p encodedText cannot be base64 decoded,
+ * @p output is reset to the starting position and the function returns NULL.
+ *
+ * @param [in,out] output The instance of {@link PARCBufferComposer} to which the decoded @p encodedText is appended
+ * @param [in] encodedText The array to be decoded and appended to @p output
+ *
+ * @return A pointer to the @p output, or NULL if the @p encodedText cannot be base64 decoded
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferComposer *parcBase64_Decode(PARCBufferComposer *output, PARCBuffer *encodedText);
+
+/**
+ * Base64 decode the string, using strlen() to get the length.
+ *
+ * @param [in,out] output The instance of {@link PARCBufferComposer} to which the decoded @p encodedText is appended
+ * @param [in] encodedString The string to be decoded and appended to @p output
+ *
+ * @return A pointer to the @p output, or NULL if the @p encodedString cannot be base64 decoded
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferComposer *parcBase64_DecodeString(PARCBufferComposer *output, const char *encodedString);
+
+/**
+ * Base64 decode the array.
+ *
+ * @param [in,out] output The instance of {@link PARCBufferComposer} to which the decoded @p array is appended
+ * @param [in] length The size of the array.
+ * @param [in] array The array to be decoded and appended to @p output
+ *
+ * @return A pointer to the @p output, or NULL if the @p encodedString cannot be base64 decoded
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferComposer *parcBase64_DecodeArray(PARCBufferComposer *output, size_t length, const uint8_t *array);
+#endif // libparc_parc_Base64_h
diff --git a/libparc/parc/algol/parc_BitVector.c b/libparc/parc/algol/parc_BitVector.c
new file mode 100755
index 00000000..578fd102
--- /dev/null
+++ b/libparc/parc/algol/parc_BitVector.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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_BitVector.h>
+#include <parc/algol/parc_Memory.h>
+
+#define BITS_PER_BYTE 8
+#define DEFAULT_BITARRAY_SIZE 1
+#define MAX_BIT_VECTOR_INDEX 8192
+
+struct PARCBitVector {
+ // the number of bits allocated.
+ unsigned bitLength;
+
+ // we track the number of "1"s set for fast computation
+ // <code>parcBitVector_NumberOfBitsSet()</code>
+ unsigned numberOfBitsSet;
+
+ // optimize case where only one bit is set.
+ unsigned firstBitSet;
+
+ // our backing memory.
+ uint8_t *bitArray;
+
+ // Fill value to be used when extending a vector
+ int fillValue;
+};
+
+static void
+_destroy(PARCBitVector **parcBitVector)
+{
+ parcMemory_Deallocate(&((*parcBitVector)->bitArray));
+}
+
+parcObject_ExtendPARCObject(PARCBitVector, _destroy, parcBitVector_Copy, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(parcBitVector, PARCBitVector);
+
+parcObject_ImplementRelease(parcBitVector, PARCBitVector);
+
+PARCBitVector *
+parcBitVector_Create(void)
+{
+ PARCBitVector *parcBitVector = parcObject_CreateInstance(PARCBitVector);
+ assertNotNull(parcBitVector, "parcObject_CreateInstance returned NULL");
+
+ parcBitVector->bitArray = parcMemory_AllocateAndClear(DEFAULT_BITARRAY_SIZE);
+ assertNotNull(parcBitVector->bitArray, "parcMemory_AllocateAndClear(%d) returned NULL", DEFAULT_BITARRAY_SIZE);
+ parcBitVector->bitLength = DEFAULT_BITARRAY_SIZE * BITS_PER_BYTE;
+ parcBitVector->numberOfBitsSet = 0;
+ parcBitVector->firstBitSet = -1;
+ parcBitVector->fillValue = 0;
+
+ return parcBitVector;
+}
+
+PARCBitVector *
+parcBitVector_Copy(const PARCBitVector *source)
+{
+ PARCBitVector *parcBitVector = parcObject_CreateInstance(PARCBitVector);
+ assertNotNull(parcBitVector, "parcObject_CreateInstance returned NULL");
+
+ size_t byteLength = source->bitLength / BITS_PER_BYTE;
+ parcBitVector->bitArray = parcMemory_Allocate(byteLength);
+ memcpy(parcBitVector->bitArray, source->bitArray, byteLength);
+ parcBitVector->bitLength = source->bitLength;
+ parcBitVector->numberOfBitsSet = source->numberOfBitsSet;
+ parcBitVector->firstBitSet = source->firstBitSet;
+ parcBitVector->fillValue = source->fillValue;
+
+ return parcBitVector;
+}
+
+bool
+parcBitVector_Equals(const PARCBitVector *a, const PARCBitVector *b)
+{
+ bool equal = ((a->numberOfBitsSet == b->numberOfBitsSet) &&
+ (a->firstBitSet == b->firstBitSet));
+
+ if (equal) {
+ int byteLength = a->bitLength / BITS_PER_BYTE;
+ if ((a->bitLength != b->bitLength) &&
+ (b->bitLength < a->bitLength)) {
+ byteLength = b->bitLength / BITS_PER_BYTE;
+ }
+ equal = (memcmp(a->bitArray, b->bitArray, byteLength) == 0);
+ }
+
+ return equal;
+}
+
+static void
+_parc_bit_vector_resize(PARCBitVector *parcBitVector, unsigned bit)
+{
+ assertNotNull(parcBitVector, "_parc_bit_vector_resize passed a NULL parcBitVector");
+ assertTrue(bit < MAX_BIT_VECTOR_INDEX, "_parc_bit_vector_resize passed a bit index that's too large");
+
+ unsigned neededBits = bit + 1;
+ if (neededBits > parcBitVector->bitLength) {
+ int newSize = (neededBits / BITS_PER_BYTE) + ((neededBits % BITS_PER_BYTE) ? 1 : 0);
+ int oldSize = (parcBitVector->bitLength / BITS_PER_BYTE) + ((parcBitVector->bitLength % BITS_PER_BYTE) ? 1 : 0);
+
+ uint8_t *newArray = parcMemory_Reallocate(parcBitVector->bitArray, newSize);
+ assertTrue(newArray, "parcMemory_Reallocate(%d) failed", newSize);
+ // Reallocate does not guarantee that additional memory is zero-filled.
+ memset((void *) &(newArray[oldSize]), parcBitVector->fillValue, newSize - oldSize);
+
+ parcBitVector->bitArray = newArray;
+ assertNotNull(newArray, "parcMemory_Reallocate(%d) returned NULL", newSize);
+ parcBitVector->bitLength = newSize * BITS_PER_BYTE;
+ }
+}
+
+int
+parcBitVector_Get(const PARCBitVector *parcBitVector, unsigned bit)
+{
+ assertTrue(bit < MAX_BIT_VECTOR_INDEX, "parcBitVector_Set passed a bit index that's too large");
+
+ if ((parcBitVector == NULL) || (bit >= parcBitVector->bitLength)) {
+ return -1;
+ }
+
+ int byte = bit / BITS_PER_BYTE;
+ int bitInByte = bit % BITS_PER_BYTE;
+ if ((parcBitVector->bitArray[byte] & (1 << bitInByte))) {
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+parcBitVector_Set(PARCBitVector *parcBitVector, unsigned bit)
+{
+ assertNotNull(parcBitVector, "parcBitVector_Set passed a NULL parcBitVector");
+ assertTrue(bit < MAX_BIT_VECTOR_INDEX, "parcBitVector_Set passed a bit index that's too huge");
+ if (bit >= parcBitVector->bitLength) {
+ _parc_bit_vector_resize(parcBitVector, bit);
+ }
+ int byte = bit / BITS_PER_BYTE;
+ int bitInByte = bit % BITS_PER_BYTE;
+ if (!(parcBitVector->bitArray[byte] & (1 << bitInByte))) {
+ parcBitVector->bitArray[byte] |= (1 << bitInByte);
+ parcBitVector->numberOfBitsSet++;
+ }
+ if ((parcBitVector->firstBitSet == -1) || (bit < parcBitVector->firstBitSet)) {
+ parcBitVector->firstBitSet = bit;
+ }
+}
+
+void
+parcBitVector_SetVector(PARCBitVector *parcBitVector, const PARCBitVector *bitsToSet)
+{
+ assertNotNull(parcBitVector, "parcBitVector_SetVector passed a NULL parcBitVector");
+ assertNotNull(parcBitVector, "parcBitVector_SetVector passed a NULL vector of bits to set");
+ int settingBit = 0;
+ for (int i = 0; i < bitsToSet->numberOfBitsSet; i++) {
+ settingBit = parcBitVector_NextBitSet(bitsToSet, settingBit);
+ assertTrue(settingBit != -1, "Number of bits claimed set inconsistent with bits found");
+ parcBitVector_Set(parcBitVector, settingBit);
+ settingBit++;
+ }
+}
+
+void
+parcBitVector_Reset(PARCBitVector *parcBitVector)
+{
+ parcBitVector->numberOfBitsSet = 0;
+ parcBitVector->firstBitSet = -1;
+ parcBitVector->fillValue = 0;
+ memset(parcBitVector->bitArray, parcBitVector->fillValue, parcBitVector->bitLength / BITS_PER_BYTE);
+}
+
+
+void
+parcBitVector_Clear(PARCBitVector *parcBitVector, unsigned bit)
+{
+ assertNotNull(parcBitVector, "parcBitVector_Clear passed a NULL parcBitVector");
+ assertTrue(bit < MAX_BIT_VECTOR_INDEX, "parcBitVector_Clear passed a bit index that's too huge");
+ if (bit > parcBitVector->bitLength) {
+ _parc_bit_vector_resize(parcBitVector, bit);
+ }
+ int byte = bit / BITS_PER_BYTE;
+ int bitInByte = bit % BITS_PER_BYTE;
+ if (parcBitVector->bitArray[byte] & (1 << bitInByte)) {
+ parcBitVector->bitArray[byte] &= ~(1 << bitInByte);
+ parcBitVector->numberOfBitsSet--;
+ }
+ if (bit == parcBitVector->firstBitSet) {
+ parcBitVector->firstBitSet = parcBitVector_NextBitSet(parcBitVector, bit + 1);
+ }
+}
+
+void
+parcBitVector_ClearVector(PARCBitVector *parcBitVector, const PARCBitVector *bitsToClear)
+{
+ assertNotNull(parcBitVector, "parcBitVector_ClearVector passed a NULL parcBitVector");
+ assertNotNull(bitsToClear, "parcBitVector_ClearVector passed a NULL for vector of bitsToClear");
+
+ // If we're clearing ourself, we just need a reset
+ if (parcBitVector == bitsToClear) {
+ parcBitVector_Reset(parcBitVector);
+ return;
+ }
+
+ int clearingBit = 0;
+ for (int i = 0; i < bitsToClear->numberOfBitsSet; i++) {
+ clearingBit = parcBitVector_NextBitSet(bitsToClear, clearingBit);
+ // only clear up to the end of the original vector
+ if (clearingBit >= parcBitVector->bitLength) {
+ return;
+ }
+ if (clearingBit != -1) {
+ parcBitVector_Clear(parcBitVector, clearingBit);
+ }
+ clearingBit++;
+ }
+}
+
+unsigned
+parcBitVector_NumberOfBitsSet(const PARCBitVector *parcBitVector)
+{
+ return parcBitVector->numberOfBitsSet;
+}
+
+unsigned
+parcBitVector_NextBitSet(const PARCBitVector *parcBitVector, unsigned startFrom)
+{
+ if (startFrom >= parcBitVector->bitLength) {
+ return -1;
+ }
+ if (startFrom <= parcBitVector->firstBitSet) {
+ return parcBitVector->firstBitSet;
+ }
+ int byte = startFrom / BITS_PER_BYTE;
+ int bitInByte = startFrom % BITS_PER_BYTE;
+ int allocatedBytes = ((parcBitVector->bitLength) / BITS_PER_BYTE);
+ for (; byte < allocatedBytes; byte++) {
+ if (parcBitVector->bitArray[byte]) {
+ for (; bitInByte < BITS_PER_BYTE; bitInByte++) {
+ if (parcBitVector->bitArray[byte] & (1 << bitInByte)) {
+ return (byte * BITS_PER_BYTE) + bitInByte;
+ }
+ }
+ }
+ bitInByte = 0;
+ }
+ return -1;
+}
+
+bool
+parcBitVector_Contains(const PARCBitVector *parcBitVector, const PARCBitVector *testVector)
+{
+ bool result = true;
+
+ int testBit = 0;
+ for (int i = 0; i < testVector->numberOfBitsSet; i++, testBit++) {
+ testBit = parcBitVector_NextBitSet(testVector, testBit);
+ if (parcBitVector_Get(parcBitVector, testBit) != 1) {
+ result = false;
+ break;
+ }
+ }
+
+ return result;
+}
+
+char *
+parcBitVector_ToString(const PARCBitVector *parcBitVector)
+{
+ char *result = NULL;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ if (composer != NULL) {
+ int nextBitSet = 0;
+ parcBufferComposer_Format(composer, "[ ");
+ for (int index = parcBitVector_NumberOfBitsSet(parcBitVector); index; index--) {
+ nextBitSet = parcBitVector_NextBitSet(parcBitVector, nextBitSet);
+ parcBufferComposer_Format(composer, "%d ", nextBitSet);
+ nextBitSet++;
+ }
+ parcBufferComposer_Format(composer, "]");
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ parcBufferComposer_Release(&composer);
+
+ result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ }
+
+ return result;
+}
+
+PARCBitVector *
+parcBitVector_Or(const PARCBitVector *first, const PARCBitVector *second)
+{
+ PARCBitVector *result = NULL;
+
+ if (first != NULL) {
+ result = parcBitVector_Copy(first);
+ if (second != NULL) {
+ for (int bit = 0; (bit = parcBitVector_NextBitSet(second, bit)) >= 0; bit++) {
+ parcBitVector_Set(result, bit);
+ }
+ }
+ } else if (second != NULL) {
+ result = parcBitVector_Copy(second);
+ } else { // both null, or is empty
+ result = parcBitVector_Create();
+ }
+
+ return result;
+}
+
+PARCBitVector *
+parcBitVector_And(const PARCBitVector *first, const PARCBitVector *second)
+{
+ PARCBitVector *result = parcBitVector_Create();
+
+ if (second == NULL) {
+ if (first != NULL) {
+ return result;
+ }
+ }
+
+ if (first != NULL) {
+ for (int bit = 0; (bit = parcBitVector_NextBitSet(first, bit)) >= 0; bit++) {
+ if (parcBitVector_Get(second, bit) == 1) {
+ parcBitVector_Set(result, bit);
+ }
+ }
+ }
+
+ return result;
+}
+
+static PARCBitVector *
+_parcBitVector_LeftShiftOnce(PARCBitVector *parcBitVector)
+{
+ if (parcBitVector != NULL) {
+ for (int bit = 0; (bit = parcBitVector_NextBitSet(parcBitVector, bit)) >= 0; bit++) {
+ if (bit > 0) { // The first bit falls off
+ parcBitVector_Set(parcBitVector, bit - 1);
+ }
+ parcBitVector_Clear(parcBitVector, bit);
+ }
+ }
+
+ return parcBitVector;
+}
+
+PARCBitVector *
+parcBitVector_LeftShift(PARCBitVector *parcBitVector, size_t count)
+{
+ for (int i = 0; i < count; i++) {
+ _parcBitVector_LeftShiftOnce(parcBitVector);
+ }
+
+ return parcBitVector;
+}
+
+static PARCBitVector *
+_parcBitVector_RightShiftOnce(PARCBitVector *parcBitVector)
+{
+ if (parcBitVector != NULL) {
+ for (int bit = 0; (bit = parcBitVector_NextBitSet(parcBitVector, bit)) >= 0; bit++) {
+ // Shift the next sequence of one bits into the first zero bit
+ int nextZero = bit + 1;
+ while (parcBitVector_Get(parcBitVector, nextZero) == 1) {
+ nextZero++;
+ }
+ parcBitVector_Clear(parcBitVector, bit++);
+ while (bit <= nextZero) {
+ parcBitVector_Set(parcBitVector, bit);
+ bit++;
+ }
+ }
+ }
+
+ return parcBitVector;
+}
+
+PARCBitVector *
+parcBitVector_RightShift(PARCBitVector *parcBitVector, size_t count)
+{
+ for (int i = 0; i < count; i++) {
+ _parcBitVector_RightShiftOnce(parcBitVector);
+ }
+
+ return parcBitVector;
+}
diff --git a/libparc/parc/algol/parc_BitVector.h b/libparc/parc/algol/parc_BitVector.h
new file mode 100755
index 00000000..7e72ac70
--- /dev/null
+++ b/libparc/parc/algol/parc_BitVector.h
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_BitVector.h
+ * @ingroup types
+ *
+ */
+#ifndef libparc_parc_BitVector_h
+#define libparc_parc_BitVector_h
+
+#include <stdbool.h>
+
+/**
+ * @typedef PARCBitVector
+ * @brief A structure containing private bit vector state data variables
+ */
+struct PARCBitVector;
+typedef struct PARCBitVector PARCBitVector;
+
+/**
+ * Create a new bit vector instance.
+ *
+ * @returns NULL on error, pointer to new vector on success.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * }
+ * @endcode
+ *
+ */
+PARCBitVector *parcBitVector_Create(void);
+
+/**
+ * Create a copy of a bit vector instance.
+ *
+ * @param [in] parcBitVector to duplicate
+ * @returns NULL on error, pointer to new copy on success.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * PARCBitVector *copy = parcBitVector_Copy(parcBitVector);
+ * assertTrue(parcBitVector_Equals(parcBitVector, copy), "Duplicate vector is unequal");
+ * }
+ * @endcode
+ *
+ */
+PARCBitVector *parcBitVector_Copy(const PARCBitVector *parcBitVector);
+
+/**
+ * Obtain a reference to a bit vector instance.
+ *
+ * @param [in] parcBitVector to obtain reference to
+ * @returns pointer to BitVector
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * PARCBitVector *reference = parcBitVector_Acquire(parcBitVector);
+ * parcBitVector_Release(&reference);
+ * parcBitVector_Release(&parcBitVector);
+ * }
+ * @endcode
+ *
+ */
+PARCBitVector *parcBitVector_Acquire(const PARCBitVector *parcBitVector);
+
+/**
+ * Release a reference to a bit vector instance.
+ *
+ * @param [in] parcBitVector to release reference to
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * PARCBitVector *reference = parcBitVector_Acquire(parcBitVector);
+ * parcBitVector_Release(&reference);
+ * parcBitVector_Release(&parcBitVector);
+ * }
+ * @endcode
+ *
+ */
+void parcBitVector_Release(PARCBitVector **parcBitVector);
+
+/**
+ * Determine equality of a pair of bit vectors
+ *
+ * @param [in] a bit vector to compare
+ * @param [in] b bit vector to compare
+ * @returns true if equal, false if unequal
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * PARCBitVector *copy = parcBitVector_Copy(parcBitVector);
+ * parcBitVector_Set(copy, 1);
+ * assertTrue(parcBitVector_Equals(parcBitVector, copy) == false, "Vector should have been unequal");
+ * }
+ * @endcode
+ *
+ */
+bool parcBitVector_Equals(const PARCBitVector *a, const PARCBitVector *b);
+
+
+/**
+ * Determine equality of a pair of bit vectors
+ *
+ * @param [in] parcBitVector bit vector to search
+ * @param [in] testVector bit vector to test
+ * @returns true if parcBitVector contains all bits in testVector, false otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *superSet = parcBitVector_Create();
+ * parcBitVector_Set(superSet, 10);
+ * parcBitVector_Set(superSet, 11);
+ * PARCBitVector *subSet = parcBitVector_Create();
+ * parcBitVector_Set(subSet, 10);
+ * assertTrue(parcBitVector_Contains(superSet, subSet), "Expect superSet to contain subSet");
+ * }
+ * @endcode
+ *
+ */
+bool parcBitVector_Contains(const PARCBitVector *parcBitVector, const PARCBitVector *testVector);
+
+/**
+ * Get the current value of a bit in a vector
+ *
+ * @param [in] parcBitVector to obtain value from
+ * @param [in] bit in vector to get value of
+ * @returns value of bit in vector, 1 or 0
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * assertTrue(parcBitVector_Get(parcBitVector, 10) == 1, "Vector should have been set");
+ * }
+ * @endcode
+ *
+ */
+int parcBitVector_Get(const PARCBitVector *parcBitVector, unsigned bit);
+
+/**
+ * Set a bit in a vector
+ *
+ * @param [in] parcBitVector to set bit in
+ * @param [in] bit in vector to set
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * assertTrue(parcBitVector_Get(parcBitVector, 10) == 1, "Vector should have been set");
+ * }
+ * @endcode
+ *
+ */
+void parcBitVector_Set(PARCBitVector *parcBitVector, unsigned bit);
+
+/**
+ * Right shift a vector contents
+ *
+ * @param [in] parcBitVector
+ * @param [in] rightShift count
+ * @param [out] input vector
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 0);
+ *
+ * parcBitVector_RightShift(parcBitVector, 1);
+ * assertTrue(parcBitVector_FirstBitSet(parcBitVector) == 1,
+ * "First vector element should have moved up");
+ *
+ * parcBitVector_Release(&parcBitVector);
+ * }
+ * @endcode
+ *
+ */
+PARCBitVector *parcBitVector_RightShift(PARCBitVector *parcBitVector, size_t rightShift);
+
+/**
+ * Left shift a vector contents
+ *
+ * @param [in] parcBitVector
+ * @param [in] leftShift count
+ * @param [out] input vector
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * parcBitVector_Set(parcBitVector, 0);
+ *
+ * parcBitVector_LeftShift(parcBitVector, 1);
+ * assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 1,
+ * "First vector element should have rolled off");
+ *
+ * parcBitVector_Release(&parcBitVector);
+ * }
+ * @endcode
+ *
+ */
+PARCBitVector *parcBitVector_LeftShift(PARCBitVector *parcBitVector, size_t leftShift);
+
+/**
+ * Logical And of a vector contents with another vector
+ *
+ * @param [in] a vector
+ * @param [in] b vector
+ * @param [out] allocated vector with result of And operation
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * PARCBitVector *andVector = parcBitVector_Create();
+ * parcBitVector_Set(andVector, 11);
+ *
+ * PARCBitVector *result = parcBitVector_And(parcBitVector, andVector);
+ * assertTrue(parcBitVector_NumberOfBitsSet(result) == 0, "Vector should have been empty");
+ *
+ * parcBitVector_Release(&parcBitVector);
+ * parcBitVector_Release(&andVector);
+ * parcBitVector_Release(&result);
+ * }
+ * @endcode
+ *
+ */
+PARCBitVector *parcBitVector_And(const PARCBitVector *a, const PARCBitVector *b);
+
+/**
+ * Logical Or of a vector contents with another vector
+ *
+ * @param [in] a vector
+ * @param [in] b vector
+ * @param [out] allocated vector with result of Or operation
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * PARCBitVector *orVector = parcBitVector_Create();
+ * parcBitVector_Set(orVector, 11);
+ *
+ * PARCBitVector *result = parcBitVector_Or(parcBitVector, orVector);
+ * assertTrue(parcBitVector_NumberOfBitsSet(result) == 2, "Vector should have been set");
+ *
+ * parcBitVector_Release(&parcBitVector);
+ * parcBitVector_Release(&orVector);
+ * parcBitVector_Release(&result);
+ * }
+ * @endcode
+ *
+ */
+PARCBitVector *parcBitVector_Or(const PARCBitVector *a, const PARCBitVector *b);
+
+/**
+ * Set a vector of bits in a vector
+ *
+ * @param [in] parcBitVector to set bits in
+ * @param [in] bitsToSet vector of bits to set
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * PARCBitVector *bitsToSet = parcBitVector_Create();
+ * parcBitVector_Set(bitsToSet, 10);
+ * parcBitVector_SetVector(parcBitVector, bitsToSet);
+ * assertTrue(parcBitVector_Get(parcBitVector, 10) == 1, "Vector should have been set");
+ * }
+ * @endcode
+ *
+ */
+void parcBitVector_SetVector(PARCBitVector *parcBitVector, const PARCBitVector *bitsToSet);
+
+/**
+ * Reset the bits of bit vector to 0
+ *
+ * @param [in] parcBitVector to set bits in
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * parcBitVector_Set(parcBitVector, 42);
+ * parcBitVector_Reset(parcBitVector);
+ * assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "Vector should have 0 bits set");
+ * }
+ * @endcode
+ *
+ */
+void parcBitVector_Reset(PARCBitVector *parcBitVector);
+
+/**
+ * Clear a bit in a vector
+ *
+ * @param [in] parcBitVector to clear bit in
+ * @param [in] bit in vector to clear
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * assertTrue(parcBitVector_Get(parcBitVector, 10) == 1, "Vector should have been set");
+ * parcBitVector_Clear(parcBitVector, 10);
+ * assertTrue(parcBitVector_Get(parcBitVector, 10) == 0, "Vector should have been cleared");
+ * }
+ * @endcode
+ *
+ */
+void parcBitVector_Clear(PARCBitVector *parcBitVector, unsigned bit);
+
+/**
+ * Clear a vector of bits in a vector
+ *
+ * @param [in] parcBitVector to clear bits in
+ * @param [in] bitsToClear vector of bits to clear
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * PARCBitVector *bitsToClear = parcBitVector_Create();
+ * parcBitVector_Set(bitsToClear, 10);
+ * parcBitVector_SetVector(parcBitVector, bitsToClear);
+ * assertTrue(parcBitVector_Get(parcBitVector, 10) == 0, "Vector should have been cleared");
+ * }
+ * @endcode
+ *
+ */
+void parcBitVector_ClearVector(PARCBitVector *parcBitVector, const PARCBitVector *bitsToClear);
+
+/**
+ * Return number of bits set in a vector
+ *
+ * @param [in] parcBitVector to return number of bits set from
+ * @returns number of bits currently set in bit vector
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 1, "One bit should have been set");
+ * }
+ * @endcode
+ *
+ */
+unsigned parcBitVector_NumberOfBitsSet(const PARCBitVector *parcBitVector);
+
+/**
+ * Return index if next set bit in vector
+ *
+ * @param [in] parcBitVector to inspect
+ * @param [in] startFrom bit position to start inspection from
+ * @returns index of next bit set in vector after startFrom or -1 if none
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 10);
+ * parcBitVector_Set(parcBitVector, 12);
+ * assertTrue(parcBitVector_NextBitSet(parcBitVector, 0) == 10, "Bit 10 should have been found first");
+ * assertTrue(parcBitVector_NextBitSet(parcBitVector, 11) == 12, "Bit 12 should have been found next");
+ * }
+ * @endcode
+ *
+ */
+unsigned parcBitVector_NextBitSet(const PARCBitVector *parcBitVector, unsigned startFrom);
+
+/**
+ * Return text representation of a bit vector
+ *
+ * @param [in] parcBitVector to represent
+ * @returns allocated character string representing bit vector which must be released by parcMemory_Deallocate
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBitVector *parcBitVector = parcBitVector_Create();
+ * parcBitVector_Set(parcBitVector, 1);
+ * const char *bitVectorString = parcBitVector_ToString(parcBitVector);
+ * printf("Vector contents: %s\n", bitVectorString);
+ * parcMemory_Deallocate(&bitVectorString);
+ * }
+ * @endcode
+ *
+ */
+char *parcBitVector_ToString(const PARCBitVector *parcBitVector);
+#endif // libparc_parc_BitVector_h
diff --git a/libparc/parc/algol/parc_Buffer.c b/libparc/parc/algol/parc_Buffer.c
new file mode 100755
index 00000000..b2ca3577
--- /dev/null
+++ b/libparc/parc/algol/parc_Buffer.c
@@ -0,0 +1,1072 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <ctype.h>
+
+#include <LongBow/runtime.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_ByteArray.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_HashCode.h>
+
+struct parc_buffer {
+ PARCByteArray *array;
+
+ size_t capacity;
+
+ size_t arrayOffset; // The offset within this buffer's backing PARCByteArray of the first element.
+
+ size_t position; // The index, relative to arrayOffset, of the next byte to be read from or written to this buffer.
+
+ /**
+ * The index, relative to arrayOffset, of the last position that cannot be read or written.
+ */
+ size_t limit;
+ /**
+ * A buffer's mark is the index, relative to arrayOffset, to which its position will be set when the reset function is invoked.
+ * The mark is not always defined, but when it is defined it is never negative and is never greater than the position.
+ * If the mark is defined then it is discarded when the position or the limit is adjusted to a value smaller than the mark.
+ * If the mark is not defined then invoking the reset function causes a trap.
+ */
+ size_t mark;
+};
+
+static inline void
+_discardMark(PARCBuffer *buffer)
+{
+ buffer->mark = SIZE_MAX;
+}
+
+static inline bool
+_markIsDiscarded(const PARCBuffer *buffer)
+{
+ return buffer->mark == SIZE_MAX;
+}
+
+static inline void
+_trapIfIndexExceedsLimit(const PARCBuffer *buffer, const size_t index)
+{
+ trapOutOfBoundsIf(index > buffer->limit, "PARCBuffer limit at %zd, attempted to access at %zd",
+ parcBuffer_Limit(buffer), index);
+}
+
+static inline void
+_trapIfBufferUnderflow(const PARCBuffer *buffer, const size_t requiredRemaining)
+{
+ _trapIfIndexExceedsLimit(buffer, buffer->position + requiredRemaining);
+}
+
+static inline size_t
+_effectiveIndex(const PARCBuffer *buffer, const size_t index)
+{
+ return buffer->arrayOffset + index;
+}
+
+static inline size_t
+_effectivePosition(const PARCBuffer *buffer)
+{
+ return buffer->arrayOffset + parcBuffer_Position(buffer);
+}
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define _optionalAssertInvariants(_instance_)
+#else
+# define _optionalAssertInvariants(_instance_) _assertInvariants(_instance_)
+
+static inline void
+_assertInvariants(const PARCBuffer *buffer)
+{
+ // 0 <= mark <= position <= limit <= capacity
+ assertTrue(0 <= buffer->mark,
+ "Expected 0 <= mark (%zd)", buffer->mark);
+ assertTrue(_markIsDiscarded(buffer) || buffer->mark <= buffer->position,
+ "Expected mark (%zd) <= position (%zd)", buffer->mark, buffer->position);
+ assertTrue(buffer->position <= buffer->limit,
+ "Expected position (%zd) <= limit (%zd)", buffer->position, buffer->limit);
+ assertTrue(buffer->limit <= buffer->capacity,
+ "Expected limit (%zd) <= capacity (%zd)", buffer->limit, buffer->capacity);
+ assertTrue((buffer->arrayOffset + buffer->capacity) <= parcByteArray_Capacity(buffer->array),
+ "Expected (%zd + %zd) <= %zd",
+ buffer->arrayOffset, buffer->capacity, parcByteArray_Capacity(buffer->array));
+}
+#endif
+
+static inline int
+_digittoint(char digit)
+{
+ int result = -1;
+
+ int value = digit - '0';
+
+ if ((unsigned) value < 10) {
+ result = value;
+ } else {
+ value = digit - 'a';
+ if ((unsigned) value < 6) {
+ result = value + 10;
+ } else {
+ value = digit - 'A';
+ if ((unsigned) value < 6) {
+ result = value + 10;
+ }
+ }
+ }
+
+ return result;
+}
+
+// This hexadecimal parsing code needs to be fixed - see FogBugz:3598
+
+static char *_hexDigitsUpper = "0123456789ABCDEF";
+static char *_hexDigitsLower = "0123456789abcdef";
+
+static inline char
+_fromHexDigit(char hexDigit)
+{
+ for (char i = 0; i < 16; i++) {
+ if (hexDigit == _hexDigitsLower[(int) i] || hexDigit == _hexDigitsUpper[(int) i]) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static inline uint8_t
+_hexByte(const char *hexByte)
+{
+ uint8_t result = (uint8_t) (_fromHexDigit(hexByte[0]) << 4) | _fromHexDigit(hexByte[1]);
+ return result;
+}
+
+static inline char *
+_parcBuffer_CheckValidity(const PARCBuffer *buffer)
+{
+ char *result = NULL;
+
+ if (buffer != NULL) {
+ if (parcObject_IsValid(buffer)) {
+ if (parcByteArray_IsValid(buffer->array)) {
+ // 0 <= mark <= position <= limit <= capacity
+ if (_markIsDiscarded(buffer) || buffer->mark <= buffer->position) {
+ if (buffer->position <= buffer->limit) {
+ if (buffer->limit <= buffer->capacity) {
+ if ((buffer->arrayOffset + buffer->capacity) <= parcByteArray_Capacity(buffer->array)) {
+ result = NULL;
+ } else {
+ result = "PARCBuffer offset+capacity exceeds the capacity of the underlying PARCByteArray";
+ }
+ } else {
+ result = "PARCBuffer limit exceeds the capacity.";
+ }
+ } else {
+ result = "PARCBuffer position exceeds the limit.";
+ }
+ } else {
+ result = "PARCBuffer mark exceeds the current position";
+ }
+ } else {
+ result = "PARCBuffer underlying PARCByteArray is invalid";
+ }
+ } else {
+ result = "PARCBuffer is an invalid PARCObject.";
+ }
+ } else {
+ result = "PARCBuffer is NULL";
+ }
+
+ return result;
+}
+
+void
+parcBuffer_AssertValid(const PARCBuffer *buffer)
+{
+ char *explanation = _parcBuffer_CheckValidity(buffer);
+
+ trapIllegalValueIf(explanation != NULL, "PARCBuffer@%p %s.", (void *) buffer, explanation);
+}
+
+bool
+parcBuffer_IsValid(const PARCBuffer *buffer)
+{
+ bool result = false;
+
+ if (buffer != NULL) {
+ if (parcObject_IsValid(buffer)) {
+ if (parcByteArray_IsValid(buffer->array)) {
+ // 0 <= mark <= position <= limit <= capacity
+ if (_markIsDiscarded(buffer) || buffer->mark <= buffer->position) {
+ if (buffer->position <= buffer->limit) {
+ if (buffer->limit <= buffer->capacity) {
+ if ((buffer->arrayOffset + buffer->capacity) <= parcByteArray_Capacity(buffer->array)) {
+ result = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static bool
+_parcBuffer_Destructor(PARCBuffer **bufferPtr)
+{
+ PARCBuffer *buffer = *bufferPtr;
+
+ parcByteArray_Release(&buffer->array);
+ return true;
+}
+
+parcObject_Override(PARCBuffer, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcBuffer_Destructor,
+ .copy = (PARCObjectCopy *) parcBuffer_Copy,
+ .toString = (PARCObjectToString *) parcBuffer_ToString,
+ .equals = (PARCObjectEquals *) parcBuffer_Equals,
+ .compare = (PARCObjectCompare *) parcBuffer_Compare,
+ .hashCode = (PARCObjectHashCode *) parcBuffer_HashCode,
+ .display = (PARCObjectDisplay *) parcBuffer_Display);
+
+/**
+ * Initialise a parcBuffer instance.
+ *
+ * The buffer's offset, position, limit and capacity are set to the given values.
+ * The mark is made invalid.
+ *
+ * @return The same pointer as `result`.
+ */
+static PARCBuffer *
+_parcBuffer_Init(PARCBuffer *result, PARCByteArray *array, size_t offset, size_t position, size_t limit, size_t capacity)
+{
+ result->array = array;
+ result->arrayOffset = offset;
+ result->position = position;
+ result->limit = limit;
+ result->capacity = capacity;
+ _discardMark(result);
+
+ parcBuffer_OptionalAssertValid(result);
+
+ return result;
+}
+
+static inline PARCBuffer *
+_parcBuffer_getInstance(void)
+{
+ PARCBuffer *result = parcObject_CreateInstance(PARCBuffer);
+
+ return result;
+}
+
+static inline size_t
+_computeNewLimit(size_t oldCapacity, size_t oldLimit, size_t newCapacity)
+{
+ size_t result = newCapacity;
+
+ bool limitIsAtCapacity = (oldLimit == oldCapacity);
+
+ if (newCapacity > oldCapacity) {
+ if (limitIsAtCapacity) {
+ result = newCapacity;
+ } else {
+ result = oldLimit;
+ }
+ } else {
+ if (limitIsAtCapacity) {
+ result = newCapacity;
+ } else {
+ result = (oldLimit < newCapacity) ? oldLimit : newCapacity;
+ }
+ }
+
+ return result;
+}
+
+static inline size_t
+_computeNewMark(size_t oldMark, size_t newLimit, size_t newCapacity)
+{
+ size_t result = oldMark;
+
+ if (oldMark != SIZE_MAX) {
+ if (oldMark > newCapacity) {
+ result = SIZE_MAX;
+ } else {
+ result = oldMark;
+ }
+
+ if (result > newLimit) {
+ result = SIZE_MAX;
+ }
+ }
+
+ return result;
+}
+
+PARCBuffer *
+parcBuffer_WrapByteArray(PARCByteArray *byteArray, size_t position, size_t limit)
+{
+ PARCBuffer *result = NULL;
+
+ // The limit cannot exceed the capacity of the PARCByteArray.
+ if (limit > parcByteArray_Capacity(byteArray)) {
+ return NULL;
+ }
+ if (byteArray != NULL) {
+ result = _parcBuffer_getInstance();
+
+ if (result != NULL) {
+ return _parcBuffer_Init(result,
+ parcByteArray_Acquire(byteArray),
+ 0, position, limit,
+ parcByteArray_Capacity(byteArray));
+ }
+ }
+
+ return result;
+}
+
+PARCBuffer *
+parcBuffer_Resize(PARCBuffer *buffer, size_t newCapacity)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ PARCByteArray *newArray = parcByteArray_Allocate(newCapacity);
+ if (newArray == NULL) {
+ return NULL;
+ }
+
+ size_t numberOfBytesToCopy = parcBuffer_Capacity(buffer);
+ if (numberOfBytesToCopy > newCapacity) {
+ numberOfBytesToCopy = newCapacity;
+ }
+
+ parcByteArray_PutBytes(newArray, 0, numberOfBytesToCopy, &parcByteArray_Array(buffer->array)[buffer->arrayOffset]);
+
+ parcByteArray_Release(&buffer->array);
+
+ buffer->array = newArray;
+ buffer->arrayOffset = 0;
+ buffer->limit = _computeNewLimit(buffer->capacity, buffer->limit, newCapacity);
+ buffer->mark = _computeNewMark(buffer->mark, buffer->limit, newCapacity);
+ buffer->capacity = newCapacity;
+ buffer->position = (buffer->position < buffer->limit) ? buffer->position : buffer->limit;
+
+ parcBuffer_OptionalAssertValid(buffer);
+
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_Allocate(size_t capacity)
+{
+ PARCByteArray *array = parcByteArray_Allocate(capacity);
+
+ if (array != NULL) {
+ PARCBuffer *result = _parcBuffer_getInstance();
+ if (result != NULL) {
+ return _parcBuffer_Init(result, array, 0, 0, capacity, capacity);
+ }
+ parcByteArray_Release(&array);
+ }
+
+ return NULL;
+}
+
+PARCBuffer *
+parcBuffer_Wrap(void *array, size_t arrayLength, size_t position, size_t limit)
+{
+ PARCBuffer *result = NULL;
+
+ if (array != NULL) {
+ PARCByteArray *byteArray = parcByteArray_Wrap(arrayLength, array);
+
+ if (byteArray != NULL) {
+ result = parcBuffer_WrapByteArray(byteArray, position, limit);
+ parcByteArray_Release(&byteArray);
+ }
+ }
+
+ return result;
+}
+
+PARCBuffer *
+parcBuffer_WrapCString(char *string)
+{
+ size_t length = strlen(string);
+ return parcBuffer_Wrap(string, length, 0, length);
+}
+
+PARCBuffer *
+parcBuffer_AllocateCString(const char *string)
+{
+ size_t length = strlen(string);
+ PARCBuffer *buffer = parcBuffer_Allocate(length + 1);
+ parcBuffer_PutArray(buffer, length, (const uint8_t *) string);
+ parcBuffer_PutUint8(buffer, 0);
+ parcBuffer_SetPosition(buffer, buffer->position - 1);
+ parcBuffer_Flip(buffer);
+
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_ParseHexString(const char *hexString)
+{
+ size_t length = strlen(hexString);
+
+ // The hex string must be an even length greater than zero.
+ if (length > 0 && (length % 2) == 1) {
+ return NULL;
+ }
+
+ PARCBuffer *result = parcBuffer_Allocate(length);
+ for (size_t i = 0; i < length; i += 2) {
+ parcBuffer_PutUint8(result, _hexByte(&hexString[i]));
+ }
+
+ return result;
+}
+
+PARCBuffer *
+parcBuffer_CreateFromArray(const void *bytes, const size_t length)
+{
+ assertTrue(length == 0 || bytes != NULL,
+ "If the byte array is NULL, then length MUST be zero.");
+
+ PARCBuffer *result = parcBuffer_Allocate(length);
+ parcBuffer_PutArray(result, length, bytes);
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcBuffer, PARCBuffer);
+
+parcObject_ImplementRelease(parcBuffer, PARCBuffer);
+
+size_t
+parcBuffer_Capacity(const PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ return buffer->capacity;
+}
+
+PARCBuffer *
+parcBuffer_Clear(PARCBuffer *buffer)
+{
+ parcBuffer_SetPosition(buffer, 0);
+ parcBuffer_SetLimit(buffer, parcBuffer_Capacity(buffer));
+ _discardMark(buffer);
+ return buffer;
+}
+
+bool
+parcBuffer_Equals(const PARCBuffer *x, const PARCBuffer *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ return (parcBuffer_Compare(x, y) == 0);
+}
+
+int
+parcBuffer_Compare(const PARCBuffer *x, const PARCBuffer *y)
+{
+ if (x == y) {
+ return 0;
+ }
+
+ if (x == NULL) {
+ return -1;
+ }
+
+ if (y == NULL) {
+ return +1;
+ }
+
+ size_t count = parcBuffer_Remaining(x);
+ if (count > parcBuffer_Remaining(y)) {
+ count = parcBuffer_Remaining(y);
+ }
+
+ int result = 0;
+
+ if (count > 0) {
+ result = memcmp(parcBuffer_Overlay((PARCBuffer *) x, 0), parcBuffer_Overlay((PARCBuffer *) y, 0), count);
+ }
+
+ if (result == 0) {
+ // This is when one buffer is longer than the other, and they are equivalent thus far.
+ ssize_t difference = parcBuffer_Remaining(x) - parcBuffer_Remaining(y);
+ if (difference > 0) {
+ result = +1;
+ } else if (difference < 0) {
+ result = -1;
+ }
+ }
+
+ return result;
+}
+
+PARCByteArray *
+parcBuffer_Array(const PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ return buffer->array;
+}
+
+PARCBuffer *
+parcBuffer_Duplicate(const PARCBuffer *original)
+{
+ PARCBuffer *result = _parcBuffer_getInstance();
+ if (result != NULL) {
+ _parcBuffer_Init(result,
+ parcByteArray_Acquire(original->array),
+ original->arrayOffset,
+ original->position,
+ parcBuffer_Limit(original),
+ original->capacity);
+
+ _optionalAssertInvariants(result);
+ }
+ return result;
+}
+
+PARCBuffer *
+parcBuffer_Slice(const PARCBuffer *original)
+{
+ PARCBuffer *result = _parcBuffer_getInstance();
+ if (result != NULL) {
+ _parcBuffer_Init(result,
+ parcByteArray_Acquire(original->array),
+ original->arrayOffset + parcBuffer_Position(original),
+ 0,
+ parcBuffer_Limit(original) - parcBuffer_Position(original),
+ parcBuffer_Limit(original) - parcBuffer_Position(original));
+
+ _optionalAssertInvariants(result);
+ }
+ return result;
+}
+
+size_t
+parcBuffer_ArrayOffset(const PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ return buffer->arrayOffset;
+}
+
+PARCBuffer *
+parcBuffer_Reset(PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ assertFalse(_markIsDiscarded(buffer),
+ "The mark has not been set");
+ buffer->position = buffer->mark;
+
+ _optionalAssertInvariants(buffer);
+
+ return buffer;
+}
+
+size_t
+parcBuffer_Limit(const PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ return buffer->limit;
+}
+
+PARCBuffer *
+parcBuffer_Mark(PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ buffer->mark = buffer->position;
+ _optionalAssertInvariants(buffer);
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_SetLimit(PARCBuffer *buffer, size_t newLimit)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+ assertTrue(newLimit <= parcBuffer_Capacity(buffer),
+ "new limit cannot be larger than the capacity");
+
+ if (_markIsDiscarded(buffer)) {
+ buffer->limit = newLimit;
+ _discardMark(buffer);
+ } else {
+ if (newLimit < buffer->position) {
+ buffer->position = newLimit;
+ }
+ if (newLimit < buffer->mark) {
+ _discardMark(buffer);
+ }
+ buffer->limit = newLimit;
+ }
+ _optionalAssertInvariants(buffer);
+ return buffer;
+}
+
+size_t
+parcBuffer_Position(const PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ return buffer->position;
+}
+
+size_t
+parcBuffer_Remaining(const PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ return buffer->limit - buffer->position;
+}
+
+bool
+parcBuffer_HasRemaining(const PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ return parcBuffer_Remaining(buffer) != 0;
+}
+
+PARCBuffer *
+parcBuffer_SetPosition(PARCBuffer *buffer, size_t newPosition)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ assertFalse(newPosition > buffer->limit,
+ "new position cannot be greater the buffer's limit");
+
+ buffer->position = newPosition;
+ if (!_markIsDiscarded(buffer) && newPosition < buffer->mark) {
+ _discardMark(buffer);
+ }
+
+ _optionalAssertInvariants(buffer);
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_Rewind(PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ buffer->position = 0;
+ _discardMark(buffer);
+
+ _optionalAssertInvariants(buffer);
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_Copy(const PARCBuffer *original)
+{
+ parcBuffer_OptionalAssertValid(original);
+
+ PARCBuffer *result = _parcBuffer_getInstance();
+
+ if (result != NULL) {
+ PARCByteArray *array = parcByteArray_Copy(original->array);
+ if (array != NULL) {
+ _parcBuffer_Init(result,
+ array,
+ parcBuffer_ArrayOffset(original),
+ parcBuffer_Position(original),
+ parcBuffer_Limit(original),
+ parcBuffer_Capacity(original));
+ } else {
+ parcBuffer_Release(&result);
+ }
+ }
+
+ return result;
+}
+
+PARCBuffer *
+parcBuffer_Flip(PARCBuffer *result)
+{
+ parcBuffer_OptionalAssertValid(result);
+
+ size_t position = result->position;
+ result->position = 0;
+ result->limit = position;
+
+ _optionalAssertInvariants(result);
+
+ return result;
+}
+
+uint8_t
+parcBuffer_GetAtIndex(const PARCBuffer *buffer, size_t index)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+
+ _trapIfIndexExceedsLimit(buffer, index);
+
+ return parcByteArray_GetByte(buffer->array, _effectiveIndex(buffer, index));
+}
+
+void *
+parcBuffer_Overlay(PARCBuffer *buffer, size_t length)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+ _trapIfBufferUnderflow(buffer, length);
+
+ uint8_t *result = parcByteArray_AddressOfIndex(buffer->array, _effectiveIndex(buffer, parcBuffer_Position(buffer)));
+ buffer->position += length;
+ return result;
+}
+
+uint8_t
+parcBuffer_GetUint8(PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+ _trapIfBufferUnderflow(buffer, 1);
+
+ uint8_t result = parcByteArray_GetByte(buffer->array, _effectivePosition(buffer));
+ buffer->position++;
+
+ return result;
+}
+
+PARCBuffer *
+parcBuffer_GetBytes(PARCBuffer *buffer, size_t length, uint8_t array[length])
+{
+ parcBuffer_OptionalAssertValid(buffer);
+ _trapIfBufferUnderflow(buffer, length);
+
+ parcByteArray_GetBytes(buffer->array, _effectivePosition(buffer), length, array);
+ buffer->position += length;
+
+ return buffer;
+}
+
+uint16_t
+parcBuffer_GetUint16(PARCBuffer *buffer)
+{
+ uint8_t high = parcBuffer_GetUint8(buffer);
+ uint8_t low = parcBuffer_GetUint8(buffer);
+
+ uint16_t result = (high << 8) | low;
+
+ return result;
+}
+
+uint32_t
+parcBuffer_GetUint32(PARCBuffer *buffer)
+{
+ uint32_t result = 0;
+ for (int i = 0; i < sizeof(uint32_t); i++) {
+ result = result << 8 | parcBuffer_GetUint8(buffer);
+ }
+ return result;
+}
+
+uint64_t
+parcBuffer_GetUint64(PARCBuffer *buffer)
+{
+ uint64_t result = 0;
+ for (int i = 0; i < sizeof(uint64_t); i++) {
+ result = result << 8 | parcBuffer_GetUint8(buffer);
+ }
+ return result;
+}
+
+PARCBuffer *
+parcBuffer_PutUint8(PARCBuffer *buffer, uint8_t value)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+ assertTrue(parcBuffer_Remaining(buffer) >= 1,
+ "Buffer overflow");
+
+ parcByteArray_PutByte(buffer->array, _effectivePosition(buffer), value);
+ buffer->position++;
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_PutUint16(PARCBuffer *buffer, uint16_t value)
+{
+ assertTrue(parcBuffer_Remaining(buffer) >= sizeof(uint16_t),
+ "Buffer overflow");
+
+ parcBuffer_PutUint8(buffer, (value >> 8) & 0xFF);
+ parcBuffer_PutUint8(buffer, value & 0xFF);
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_PutUint32(PARCBuffer *buffer, uint32_t value)
+{
+ assertTrue(parcBuffer_Remaining(buffer) >= sizeof(uint32_t),
+ "Buffer overflow");
+ for (int i = sizeof(uint32_t) - 1; i > 0; i--) {
+ uint8_t b = value >> (i * 8) & 0xFF;
+ parcBuffer_PutUint8(buffer, b);
+ }
+ parcBuffer_PutUint8(buffer, value & 0xFF);
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_PutUint64(PARCBuffer *buffer, uint64_t value)
+{
+ assertTrue(parcBuffer_Remaining(buffer) >= sizeof(uint64_t),
+ "Buffer overflow");
+ for (int i = sizeof(uint64_t) - 1; i > 0; i--) {
+ uint8_t b = value >> (i * 8) & 0xFF;
+ parcBuffer_PutUint8(buffer, b);
+ }
+ parcBuffer_PutUint8(buffer, value & 0xFF);
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_PutAtIndex(PARCBuffer *buffer, size_t index, uint8_t value)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+ assertTrue(_effectiveIndex(buffer, index) < parcBuffer_Limit(buffer), "Buffer overflow");
+
+ parcByteArray_PutByte(buffer->array, _effectiveIndex(buffer, index), value);
+ return buffer;
+}
+
+PARCBuffer *
+parcBuffer_PutArray(PARCBuffer *buffer, size_t arrayLength, const uint8_t array[arrayLength])
+{
+ parcBuffer_OptionalAssertValid(buffer);
+ assertTrue(parcBuffer_Remaining(buffer) >= arrayLength,
+ "Buffer overflow");
+
+ parcByteArray_PutBytes(buffer->array, _effectivePosition(buffer), arrayLength, array);
+ return parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) + arrayLength);
+}
+
+PARCBuffer *
+parcBuffer_PutCString(PARCBuffer *buffer, const char *string)
+{
+ return parcBuffer_PutArray(buffer, strlen(string) + 1, (const uint8_t *) string);
+}
+
+PARCBuffer *
+parcBuffer_PutBuffer(PARCBuffer *result, const PARCBuffer *buffer)
+{
+ parcBuffer_OptionalAssertValid(buffer);
+ assertTrue(parcBuffer_Remaining(result) >= parcBuffer_Remaining(buffer),
+ "Buffer overflow. %zd bytes remaining, %zd required.", parcBuffer_Remaining(result), parcBuffer_Remaining(buffer));
+
+ size_t length = parcBuffer_Remaining(buffer);
+ parcByteArray_ArrayCopy(result->array, _effectivePosition(result), buffer->array, _effectivePosition(buffer), length);
+ parcBuffer_SetPosition(result, parcBuffer_Position(result) + length);
+ return result;
+}
+
+PARCHashCode
+parcBuffer_HashCode(const PARCBuffer *buffer)
+{
+ PARCHashCode result = 0;
+
+ size_t remaining = parcBuffer_Remaining(buffer);
+ if (remaining > 0) {
+ result = parcHashCode_Hash(parcBuffer_Overlay((PARCBuffer *) buffer, 0), parcBuffer_Remaining(buffer));
+ }
+ return result;
+}
+
+size_t
+parcBuffer_FindUint8(const PARCBuffer *buffer, uint8_t byte)
+{
+ for (size_t i = parcBuffer_Position(buffer); i < parcBuffer_Limit(buffer); i++) {
+ if (parcBuffer_GetAtIndex(buffer, i) == byte) {
+ return i;
+ }
+ }
+ return SIZE_MAX;
+}
+
+char *
+parcBuffer_ToString(const PARCBuffer *buffer)
+{
+ size_t remaining = parcBuffer_Remaining(buffer);
+
+ char *result = parcMemory_Allocate(remaining + 1);
+ if (remaining > 0) {
+ assertNotNull(result, "parcMemory_Allocate returned NULL");
+ if (result != NULL) {
+ memcpy(result, parcBuffer_Overlay((PARCBuffer *) buffer, 0), remaining);
+ }
+ }
+ result[remaining] = 0;
+ return result;
+}
+
+void
+parcBuffer_Display(const PARCBuffer *buffer, int indentation)
+{
+ if (buffer == NULL) {
+ parcDisplayIndented_PrintLine(indentation, "PARCBuffer@NULL");
+ } else {
+ parcDisplayIndented_PrintLine(indentation, "PARCBuffer@%p {", (void *) buffer);
+ parcDisplayIndented_PrintLine(indentation + 1,
+ ".arrayOffset=%zd .position=%zd .limit=%zd .mark=%zd",
+ buffer->arrayOffset, buffer->position, buffer->limit, buffer->mark);
+ parcByteArray_Display(buffer->array, indentation + 1);
+ parcDisplayIndented_PrintLine(indentation, "}");
+ }
+}
+
+// Given a value, return the low nibble as a hex character.
+static char
+_toHexDigit(const char value)
+{
+ return "0123456789ABCDEF"[value & 0xF];
+}
+
+char *
+parcBuffer_ToHexString(const PARCBuffer *buffer)
+{
+ if (buffer == NULL) {
+ return parcMemory_StringDuplicate("null", 4);
+ }
+
+ size_t length = parcBuffer_Remaining(buffer);
+ // Hopefully length is less than (2^(sizeof(size_t)*8) / 2)
+
+ char *result = parcMemory_AllocateAndClear((length * 2) + 1);
+ assertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", (length * 2) + 1);
+
+ for (size_t i = 0; i < length; i++) {
+ unsigned char byte = parcBuffer_GetAtIndex(buffer, i);
+ result[i * 2] = _toHexDigit(byte >> 4);
+ result[i * 2 + 1] = _toHexDigit(byte);
+ }
+ result[length * 2] = 0;
+
+ return result;
+}
+
+bool
+parcBuffer_SkipOver(PARCBuffer *buffer, size_t length, const uint8_t bytesToSkipOver[length])
+{
+ while (parcBuffer_Remaining(buffer) > 0) {
+ uint8_t character = parcBuffer_GetUint8(buffer);
+ if (memchr(bytesToSkipOver, character, length) == NULL) {
+ parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) - 1);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+parcBuffer_SkipTo(PARCBuffer *buffer, size_t length, const uint8_t bytesToSkipTo[length])
+{
+ bool result = false;
+
+ while (parcBuffer_Remaining(buffer) > 0) {
+ uint8_t character = parcBuffer_GetUint8(buffer);
+ if (memchr(bytesToSkipTo, character, length) != NULL) {
+ parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) - 1);
+ result = true;
+ break;
+ }
+ }
+ return result;
+}
+
+uint8_t
+parcBuffer_PeekByte(const PARCBuffer *buffer)
+{
+ return parcBuffer_GetAtIndex(buffer, parcBuffer_Position(buffer));
+}
+
+uint64_t
+parcBuffer_ParseHexNumber(PARCBuffer *buffer)
+{
+ char *bytes = parcBuffer_Overlay(buffer, 0);
+
+ int start = 0;
+ if (parcBuffer_Remaining(buffer) > 2) {
+ if (bytes[0] == '0' && bytes[1] == 'x') {
+ start = 2;
+ }
+ }
+
+ unsigned count = 0;
+ uint64_t result = 0;
+ for (int i = start; i < parcBuffer_Remaining(buffer) && isxdigit(bytes[i]); i++) {
+ result = (result * 16) + _digittoint(bytes[i]);
+ count++;
+ }
+
+ parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) + start + count);
+
+ return result;
+}
+
+uint64_t
+parcBuffer_ParseDecimalNumber(PARCBuffer *buffer)
+{
+ char *bytes = parcBuffer_Overlay(buffer, 0);
+
+ int start = 0;
+
+ unsigned count = 0;
+ uint64_t result = 0;
+ for (int i = start; i < parcBuffer_Remaining(buffer) && isdigit(bytes[i]); i++) {
+ result = (result * 10) + _digittoint(bytes[i]);
+ count++;
+ }
+
+ parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) + count);
+
+ return result;
+}
+
+uint64_t
+parcBuffer_ParseNumeric(PARCBuffer *buffer)
+{
+ uint64_t result = 0;
+
+ char *bytes = parcBuffer_Overlay(buffer, 0);
+
+ if (parcBuffer_Remaining(buffer) > 2 && bytes[0] == '0' && bytes[1] == 'x') {
+ result = parcBuffer_ParseHexNumber(buffer);
+ } else {
+ result = parcBuffer_ParseDecimalNumber(buffer);
+ }
+
+ return result;
+}
diff --git a/libparc/parc/algol/parc_Buffer.h b/libparc/parc/algol/parc_Buffer.h
new file mode 100644
index 00000000..2c7f56fd
--- /dev/null
+++ b/libparc/parc/algol/parc_Buffer.h
@@ -0,0 +1,1665 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Buffer.h
+ * @ingroup memory
+ * @brief An indexable, linear buffer of bytes.
+ *
+ * A `PARCBuffer` is a linear, finite sequence of bytes.
+ * The essential properties of a buffer are its content, its capacity, limit, and position:
+ *
+ * @htmlonly
+ * <svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" version="1.1" viewBox="48 143 304 126" width="304pt" height="126pt">
+ * <defs>
+ * <font-face font-family="Helvetica Neue" font-size="10" panose-1="2 0 5 3 0 0 0 2 0 4" units-per-em="1000" underline-position="-100" underline-thickness="50" slope="0" x-height="517" cap-height="714" ascent="951.99585" descent="-212.99744" font-weight="500">
+ * <font-face-src>
+ * <font-face-name name="HelveticaNeue"/>
+ * </font-face-src>
+ * </font-face>
+ * <marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="black">
+ * <g>
+ * <path d="M 8 0 L 0 -3 L 0 3 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/>
+ * </g>
+ * </marker>
+ * </defs>
+ * <g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
+ * <title>icon_512x512</title>
+ * <rect fill="white" width="512" height="512"/>
+ * <g>
+ * <title>Layer 1</title>
+ * <text transform="translate(73 231.5)" fill="black">
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x=".055" y="10" textLength="13.37">Off</tspan>
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x="13.425" y="10" textLength="13.52">set</tspan>
+ * </text>
+ * <text transform="translate(178.5 231)" fill="black">
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x=".445" y="10" textLength="36.11">Position</tspan>
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x="7.2" y="22" textLength="22.6">Mark</tspan>
+ * </text>
+ * <text transform="translate(294 231.5)" fill="black">
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x=".16" y="10" textLength="21.68">Limit</tspan>
+ * </text>
+ * <text transform="translate(271 157.5)" fill="black">
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x=".185" y="10" textLength="39.63">Capacity</tspan>
+ * </text>
+ * <text transform="translate(83 157.5)" fill="black">
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x=".245" y="10" textLength="23.51">Array</tspan>
+ * </text>
+ * <path d="M 78 165.48333 C 73.6671 165.98884 67.757544 163.49623 65 167 C 63.49089 168.91749 62.925312 172.63153 62.52875 176.66717" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <rect x="59" y="187" width="281" height="13" fill="#205469"/>
+ * <rect x="59" y="187" width="281" height="13" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <path d="M 316 166.11628 C 321.9994 166.74412 330.42197 164.60163 334 168 C 335.8631 169.76954 336.41326 173.04195 336.67595 176.64326" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <rect x="116" y="181" width="160" height="27" fill="#f60"/>
+ * <rect x="116" y="181" width="160" height="27" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <path d="M 105 234.05085 C 108.6663 233.3673 114.16685 236.34137 116 232 C 117.15073 229.27477 116.856755 223.66586 116.47841 217.88884" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <path d="M 289 235.56897 C 284.6671 235.04603 278.16645 238.59437 276 234 C 274.57827 230.98495 275.02256 224.46193 275.496 217.88448" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <line x1="173.5" y1="232.84568" x2="125.08789" y2="211.92687" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <line x1="220.5" y1="232.58861" x2="266.94855" y2="212.01014" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * </g>
+ * </g>
+ * </svg>
+ * @endhtmlonly
+ *
+ * * A buffer's capacity is the number of bytes it contains.
+ * The capacity of a buffer is never negative and never changes.
+ *
+ * * A buffer's limit is the index of the first byte that should not be read or written.
+ * A buffer's limit is never negative and is never greater than its capacity.
+ *
+ * * A buffer's position is a cursor to or index of the next byte to be read or written.
+ * A buffer's position is never negative and is never greater than its limit.
+ *
+ * A PARCBuffer's capacity may be larger than the extent of data manipulated by the buffer.
+ * The extent of the data manipulated by the buffer is manipulated via:
+ * * {@link parcBuffer_Position},
+ * * {@link parcBuffer_SetPosition},
+ * * {@link parcBuffer_Limit},
+ * * {@link parcBuffer_SetLimit} and
+ * * {@link parcBuffer_Flip}.
+ *
+ * Strictly speaking, these relations are always true: _0 <= mark <= position <= limit <= capacity_
+ *
+ * The general model for use is to:
+ * * Create a buffer using a form of {@link parcBuffer_Allocate} or {@link parcBuffer_Wrap}.
+ * * Optionally insert data into the buffer via put operations,
+ * ultimately setting the position at the end of the valid data.
+ * * 'Flip' the buffer using the {@link parcBuffer_Flip} function to set the position to 0 and the limit at the end
+ * of the valid data.
+ * * Optionally get data from the buffer via one of the many get operations.
+ * * Use {@link parcBuffer_Rewind} function to set the position to 0 again, leaving the limit at the end of the valid data.
+ *
+ * Data is placed into a `PARCBuffer` via `Put` functions, and retreived from the buffer via `Get` operations.
+ * Both `Put` and `Get` perform their operations at the position of the buffer and update the position to the location of the
+ * next element of data.
+ * Both `Put` and `Get` operations have a full compliment of intrinsic data types that operate on data at
+ * relative positions in the buffer.
+ *
+ * The function {@link parcBuffer_GetAtIndex} provides absolute index access to the buffer for bytes.
+ *
+ * * {@link parcBuffer_PutUint8},
+ * * {@link parcBuffer_PutUint16},
+ * * {@link parcBuffer_PutUint32},
+ * * {@link parcBuffer_PutUint64},
+ * * {@link parcBuffer_PutAtIndex}
+ *
+ * * {@link parcBuffer_GetUint8},
+ * * {@link parcBuffer_GetUint16},
+ * * {@link parcBuffer_GetUint32},
+ * * {@link parcBuffer_GetUint64},
+ * * {@link parcBuffer_GetAtIndex}
+ *
+ */
+#ifndef libparc_parc_Buffer_h
+#define libparc_parc_Buffer_h
+
+typedef struct parc_buffer PARCBuffer;
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_ByteArray.h>
+
+extern parcObjectDescriptor_Declaration(PARCBuffer);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcBuffer_OptionalAssertValid(_instance_)
+#else
+# define parcBuffer_OptionalAssertValid(_instance_) parcBuffer_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that an instance of `PARCBuffer` 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] instance A pointer to a `PARCBuffer` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(64);
+ *
+ * parcBuffer_AssertValid(array);
+ * }
+ * @endcode
+ * @see parcBuffer_OptionalAssertValid
+ */
+void parcBuffer_AssertValid(const PARCBuffer *instance);
+
+/**
+ * Determine if an instance of `PARCBuffer` 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] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(64);
+ *
+ * if (parcBuffer_IsValid(buffer)) {
+ * printf("Buffer is valid.\n");
+ * }
+ * }
+ * @endcode
+ */
+bool parcBuffer_IsValid(const PARCBuffer *buffer);
+
+/**
+ * Create a new instance of `PARCBuffer` using dynamically allocated memory.
+ *
+ * The new buffer's position will be zero,
+ * its limit will be set to `length`,
+ * its mark will be undefined,
+ * and each of its elements will be initialized to zero.
+ *
+ * If capacity is zero, the buffer contains no underlying byte array.
+ *
+ * @param [in] capacity The number of bytes to allocate.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a `PARCBuffer` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(64);
+ *
+ * parcBuffer_Release(&&buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Allocate(size_t capacity);
+
+/**
+ * Create a new instance of `PARCBuffer` using using program supplied static memory (rather than allocated).
+ *
+ * The new buffer will be backed by the given array, @p array.
+ * Modifications to the buffer will cause the array to be modified and vice versa.
+ *
+ * The new buffer's capacity will be @p arrayLength,
+ * its initial position will be @p position ,
+ * the index of the first byte that should not be read or written will be @p limit,
+ * and its mark will be undefined.
+ *
+ * In all cases, _0 <= position <= limit <= capacity_
+ *
+ * Its backing array will be the given array, starting at index 0 of that array.
+ *
+ * @param [in] array A pointer to a memory array.
+ * @param [in] arrayLength The length, in `uint8_t` units, of the memory array.
+ * @param [in] position The initial value for the buffer's position.
+ * @param [in] limit The initial value for the buffer's limit.
+ *
+ * @return A `PARCBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[64];
+ *
+ * PARCBuffer *buffer = parcBuffer_Wrap(array, sizeof(array), 0, sizeof(array));
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Allocate
+ * @see parcBuffer_Release
+ */
+PARCBuffer *parcBuffer_Wrap(void *array, size_t arrayLength, size_t position, size_t limit);
+
+/**
+ * Create a new instance of `PARCBuffer` using referencing the given {@link PARCByteArray}.
+ *
+ * A reference to the `PARCByteArray` is acquired.
+ *
+ * The new buffer will be backed by the given `PARCByteArray`.
+ * Modifications to the buffer will cause the array to be modified and vice versa.
+ *
+ * The new buffer's capacity will be @p arrayLength,
+ * its initial position will be @p position ,
+ * the index of the first byte that should not be read or written will be @p limit,
+ * and its mark will be undefined.
+ *
+ * In all cases, _0 <= position <= limit <= capacity_
+ *
+ * The new buffer's
+ * capacity will be the length of the `PARCByteArray`,
+ * its initial position will be @p position ,
+ * the index of the first byte that should not be read or written will be @p limit,
+ * and its mark will be undefined.
+ *
+ * @param [in] byteArray A pointer to a `PARCByteArray` instance.
+ * @param [in] position The initial value for the buffer's position.
+ * @param [in] limit The initial value for the buffer's limit which must be less than or equal to the PARCByteArray's capacity.
+ *
+ * @return A `PARCBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCByteArray *array = parcByteArray_Allocate(64);
+ *
+ * PARCBuffer *buffer = parcBuffer_WrapByteArray(array, 0, parcByteArray_Capacity(array));
+ *
+ * parcBuffer_Release(&&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Allocate
+ * @see parcBuffer_Wrap
+ */
+PARCBuffer *parcBuffer_WrapByteArray(PARCByteArray *byteArray, size_t position, size_t limit);
+
+/**
+ * Create a new instance of `PARCBuffer` wrapping the given null-terminated C string as its value.
+ *
+ * The new buffer's capacity will be the length of the string excluding the terminating nul character.
+ * its initial position will be 0,
+ * the index of the first byte that should not be read or written will be @p limit,
+ * and its mark will be undefined.
+ *
+ * @param [in] string A pointer to a C-string to copy and then wrap.
+ *
+ * @return A `PARCBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Allocate
+ * @see parcBuffer_Wrap
+ */
+PARCBuffer *parcBuffer_WrapCString(char *string);
+
+/**
+ * Create a new instance of a `PARCBuffer` copying the given null-terminated C string as its value.
+ *
+ * The new buffer's capacity will be the length of the string excluding the terminating nul character.
+ * its initial position will be 0,
+ * the index of the first byte that should not be read or written will be @p limit,
+ * and its mark will be undefined.
+ *
+ * @param [in] string A pointer to C-string to copy and then wrap.
+ *
+ * @return A `PARCBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCByteArray *buffer = parcBuffer_AllocateCString("test string");
+ *
+ * parcBUffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_AllocateCString(const char *string);
+
+/**
+ * Create a `PARCBuffer` initalised with a copy of the contents of given byte array.
+ *
+ * The length must be non-negative (> 0) and the array pointer must not be NULL.
+ * The contents of the given array are used to initialize the `PARCBuffer` instance,
+ * and the size of the new instance is equal to the specified length (just wide enough to fit the array).
+ *
+ * @param [in] bytes A pointer to an array of bytes.
+ * @param [in] length The number of bytes to copy to the `PARCBuffer`.
+ *
+ * @return A newly allocated `PARCBuffer` instance that must be freed via `parcBuffer_Release()`.
+ *
+ * Example:
+ * @code
+ * {
+ * unsigned char array[] = { 1, 2, 3, 4, 5 };
+ * PARCBuffer *buffer = parcBuffer_CreateFromArray(array, sizeof(array));
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_CreateFromArray(const void *bytes, size_t length);
+
+/**
+ * Parse a null-terminated hexadecimal string to create a new `PARCBuffer` instance.
+ *
+ * The hex string must be null-terminated so parsing is deterministic and correct.
+ * The hex string parameter is not modified in any way.
+ * The hex string must be an even length greater than zero.
+ *
+ * @param [in] hexString The hex string to parse.
+ *
+ * @return NULL The string could not be parsed
+ * @return A new `PARCElasticBuffer` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * char *expected = "0123456789ABCDEF";
+ * PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_ParseHexString(expected));
+ * printf("String: %s\n", parcBuffer_ToString(buffer));
+ *
+ * parcBuffer_Release(buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_ParseHexString(const char *hexString);
+
+/**
+ * Increase or decrease the capacity of an existing PARCBuffer.
+ *
+ * If the new capacity is greater than the old capacity and the limit is currently set to the old capacity,
+ * then set the new limit to the new capacity.
+ * Otherwise, if the limit is not currently set to the capacity, then leave the limit unchanged.
+ *
+ * If the new capacity is less than the old capacity and the limit is currently set to the old capacity,
+ * then set the new limit to the new capacity.
+ * Otherwise, set the limit to the the lesser of the old limit or the new capacity.
+ * If the limit is not currently set to the capacity,
+ * the set the limit to the the lesser of the old limit or the new capacity.
+ *
+ * If the original mark exceeds the new limit, the new mark is invalidated and any subsequent
+ * operation on the resulting `PARCBuffer` that requires the mark will abort until the mark
+ * is set again via `parcBuffer_Mark`.
+ *
+ * If the original position of the buffer is beyond the new limit of the buffer, the position is set to the new limit.
+ *
+ * The contents of the old buffer are preserved from the origin to the new limit.
+ *
+ * This operation may induce a memory copy.
+ * As a consequence, any `PARCBuffer` instances previously created via {@link parcBuffer_Slice}
+ * refer to memory previously used by this `PARCBuffer`.
+ *
+ * A PARCBuffer originally created via any of the `parcBuffer_Wrap` forms,
+ * may no longer refer to the original wrapped data.
+ *
+ * @param [in] buffer A pointer to a valid `PARCBuffer` instance.
+ * @param [in] capacity The new capacity of `PARCBuffer`
+ *
+ * @return PARCBuffer A new `PARCBuffer` instance initialized with the contents of the given buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ * parcBuffer_Resize(buffer, 4);
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Allocate
+ * @see parcBuffer_Wrap
+ */
+PARCBuffer *parcBuffer_Resize(PARCBuffer *buffer, size_t capacity);
+
+/**
+ * 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] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The input `PARCBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *x = parcBuffer_Allocate(10);
+ *
+ * PARCBuffer *x_2 = parcBuffer_Acquire(x);
+ *
+ * parcBuffer_Release(&x);
+ * parcBuffer_Release(&x_2);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Acquire(const PARCBuffer *buffer);
+
+/**
+ * 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
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+void parcBuffer_Release(PARCBuffer **bufferPtr);
+
+/**
+ * Returns this buffer's capacity.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The given buffer's capacity.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ *
+ * size_t capacity = parcBuffer_Capacity(buffer);
+ *
+ * parcBuffer_Release(&capacity);
+ * }
+ * @endcode
+ */
+size_t parcBuffer_Capacity(const PARCBuffer *buffer);
+
+/**
+ * Clear the given buffer restoring it to its initial state:
+ * The position is set to zero,
+ * the limit is set to the capacity,
+ * and the mark is invalidated.
+ *
+ * The mark is made invalid and any subsequent operation on the resulting
+ * `PARCBuffer` that requires the mark will abort until the mark
+ * is set again via `parcBuffer_Mark`.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The value of @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * parcBuffer_Clear(buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Clear(PARCBuffer *buffer);
+
+/**
+ * Determine if two `PARCBuffer` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCBuffer` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcBuffer_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcBuffer_Equals(x, y)` must return true if and only if
+ * `parcBuffer_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcBuffer_Equals(x, y)` returns true and
+ * `parcBuffer_Equals(y, z)` returns true,
+ * then `parcBuffer_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcBuffer_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcBuffer_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] x A pointer to a `PARCBuffer` instance.
+ * @param [in] y A pointer to a `PARCBuffer` instance.
+ *
+ * @return true `PARCBuffers` x and y are equal.
+ * @return false `PARCBuffers` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *bufferA = parcBuffer_Allocate(10);
+ * PARCBuffer *bufferB = parcBuffer_Allocate(10);
+ *
+ * if (parcBuffer_Equals(bufferA, bufferB)) {
+ * printf("Buffers are equal.\n");
+ * } else {
+ * printf("Buffers are NOT equal.\n");
+ * }
+ *
+ * parcBuffer_Release(&bufferA);
+ * parcBuffer_Release(&bufferB);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_HashCode
+ */
+bool parcBuffer_Equals(const PARCBuffer *x, const PARCBuffer *y);
+
+/**
+ * Compares instance a with instance b for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as instance
+ * a is less than, equal to, or greater than instance b.
+ *
+ * The buffer's position, limit, and mark are not modified.
+ *
+ * @param [in] a A pointer to the first instance of `PARCBuffer`.
+ * @param [in] b A pointer to the second instance of `PARCBuffer`.
+ *
+ * @return <0 Instance a is less than instance b.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *bufferA = parcBuffer_Allocate(10);
+ * PARCBuffer *bufferB = parcBuffer_Allocate(10);
+ *
+ * if (parcBuffer_Compare(bufferA, bufferB) == 0) {
+ * printf("Buffers are equal.\n");
+ * }
+ *
+ * parcBuffer_Release(&bufferA);
+ * parcBuffer_Release(&bufferB);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Equals
+ */
+int parcBuffer_Compare(const PARCBuffer *a, const PARCBuffer *b);
+
+/**
+ * Return a pointer to the {@link PARCByteArray} that backs this buffer.
+ *
+ * If this `PARCBuffer` has a capacity of zero,
+ * there is no array of bytes and this function returns NULL.
+ *
+ * Modifications to the contents of the `PARCByteArray` will visible to the given
+ * `PARCBuffer` and vice-versa.
+ *
+ * The origin of the given `PARCBuffer` may not be the same as the origin of the underlying
+ * `PARCByteArray`.
+ * Use {@link parcBuffer_ArrayOffset} to obtain the origin of the given `PARCBuffer`
+ * relative to the origin of the underlying `PARCByteArray`
+ *
+ * The caller must obtain its own reference to the `PARCByteArray` if it intends to store it elsewhere.
+ *
+ * Note: Many hard to find bugs can be caused by using this function.
+ * Use the functions provided to manipulate the `PARCBuffer` and its contents.
+ *
+ * @param [in] buffer A `PARCBuffer` pointer.
+ *
+ * @return NULL There is no `PARCByteArray` backing the given `PARCBuffer` (no capacity).
+ * @return non-NULL The pointer to the `PARCByteArray` for the given `PARCBuffer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ *
+ * PARCByteArray *array = parcBuffer_Array(buffer);
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcByteArray_Acquire
+ */
+PARCByteArray *parcBuffer_Array(const PARCBuffer *buffer);
+
+/**
+ * Create an independent copy the given `PARCBuffer`
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCBuffer` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ *
+ * PARCBuffer *copy = parcBuffer_Copy(buffer);
+ *
+ * parcBuffer_Release(&copy);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ */
+PARCBuffer *parcBuffer_Copy(const PARCBuffer *buffer);
+
+/**
+ * Creates a new buffer that shares the original buffer's content.
+ *
+ * The content of the new buffer will be that of this buffer.
+ * Changes to the buffer's content will be visible in both buffers,
+ * however the two buffers' position, limit, and mark values will be independent.
+ *
+ * The new buffer's capacity, limit, position, and mark values will be identical to those of the original buffer.
+ *
+ * @param [in] original The orignal PARCBuffer instance that will be duplicated.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to ta valid `PARCBuffer` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_Duplicate(buffer2);
+ *
+ * parcBuffer_Release(&buffer);
+ * parcBuffer_Release(&buffer2);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Duplicate(const PARCBuffer *original);
+
+/**
+ * Returns the offset within this buffer's backing {@link PARCByteArray} of the first element.
+ *
+ * Buffer position <i>p</i> corresponds to array index <i>p + arrayOffset()</i>.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return `size_t` The offset within this `PARCBuffer`'s array of the first element of the buffer
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ *
+ * size_t arrayOffset = parcBuffer_ArrayOffset(buffer);
+ * // offset will be 0 since the contents of the buffer start at the beginning
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+size_t parcBuffer_ArrayOffset(const PARCBuffer *buffer);
+
+/**
+ * Rewinds this `PARCBuffer`: The position is set to zero and the mark is invalidated.
+ *
+ * The mark is made invalid and any subsequent operation on the resulting
+ * `PARCBuffer` that requires the mark will abort until the mark
+ * is set again via `parcBuffer_Mark`.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The given `PARCBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ *
+ * parcBuffer_Rewind(buffer); // bring it back to zero
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Rewind(PARCBuffer *buffer);
+
+/**
+ * Resets the given `PARCBuffer`'s position to the previously-marked position.
+ *
+ * Invoking this method neither changes nor invalidates the mark's value.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The given `PARCBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ *
+ * buffer = parcBuffer_Reset(buffer);
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Reset(PARCBuffer *buffer);
+
+/**
+ * Return the given `PARCBuffer`'s limit.
+ *
+ * A buffer's limit is the index of the first element that should not be read or written.
+ * A buffer's limit is never negative and is never greater than its capacity.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The given `PARCBuffer`'s limit.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ *
+ * size_t limit = parcBuffer_Limit(buffer);
+ * // limit will be 10
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+size_t parcBuffer_Limit(const PARCBuffer *buffer);
+
+/**
+ * Sets this buffer's mark at its position.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The value of @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ * parcBuffer_Mark(buffer);
+ * // since the position was 0, the mark remains at 0
+ *
+ * ...
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Mark(PARCBuffer *buffer);
+
+/**
+ * Sets this `PARCBuffer`'s limit.
+ *
+ * If the position is larger than the new limit then it is set to the new limit.
+ *
+ * If the mark is defined and larger than the new limit then the mark is invalidated and
+ * any subsequent operation that requires the mark will abort until the mark
+ * is set again via `parcBuffer_Mark`
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ * @param newLimit The new limit value; must be no larger than this `PARCBuffer`'s capacity.
+ *
+ * @return The given `PARCBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ *
+ * parcBuffer_SetLimit(buffer, 8);
+ *
+ * size_t limit = parcBuffer_Limit(buffer);
+ * size_t capacity = parcBuffer_Capacity(buffer);
+ * // capacity is 10, limit is 8
+ *
+ * ...
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_SetLimit(PARCBuffer *buffer, size_t newLimit);
+
+/**
+ * Return a pointer to buffer memory starting the buffer's current position.
+ *
+ * The @p length parameter must be less than or equal to the remaining bytes in the buffer
+ * and has no effect on the return value,
+ * except that if the buffer's position is equal to the limit, then this traps with OutOfBounds
+ *
+ * The current position of the buffer is advanced by @p length bytes.
+ * It is acceptable for the @p length parameter to be zero,
+ * thereby causing the current position to remain unchanged.
+ *
+ * This does not guarantee any particular memory alignment.
+ * Therefore, it is possible to obtain a pointer to memory that cannot be accessed
+ * as a native type because of CPU architecture alignment requirements.
+ *
+ * The function returns a pointer to contiguous memory within a `PARCBuffer`,
+ * but does not acquire a reference to the `PARCBuffer` instance,
+ * the underlying {@link PARCByteArray}, nor the actual memory array.
+ * If the {@link PARCBuffer} or the underlying {@link PARCByteArray} is released finally,
+ * the result from a previous call to `parcBuffer_Overlay` will point to undefined values.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ * @param [in] length The number of bytes to advance the buffer's position.
+ *
+ * @return non-NULL A pointer to memory.
+ *
+ * Example:
+ * @code
+ * {
+ * char *expected = "Hello World";
+ * struct timeval theTime = { .tv_sec = 123, .tv_usec = 456};
+ *
+ * PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint16_t) + strlen(expected) + sizeof(theTime));
+ *
+ * parcBuffer_PutUint16(buffer, strlen(expected));
+ * parcBuffer_PutUint8(buffer, expected, strlen(expected));
+ * parcBuffer_PutUint8(buffer, &theTime, sizeof(theTime));
+ * parcBuffer_Flip();
+ *
+ * uint16_t length = parcBuffer_GetUint16(buffer);
+ * char *actual = parcBuffer_Overlay(buffer, length);
+ * struct timeval *tm = parcBuffer_Overlay(buffer, sizeof(struct timeval));
+ * }
+ * @endcode
+ */
+void *parcBuffer_Overlay(PARCBuffer *buffer, size_t length);
+
+/**
+ * Return the given `PARCBuffer`'s position.
+ *
+ * A buffer's position is the index of the next element to be read or written.
+ * A buffer's position is never negative and is never greater than its limit.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ * @return The given `PARCBuffer`'s position.
+ *
+ * Example:
+ * @code
+ * {
+ * size_t currentPosition = parcBuffer_Position(buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_SetPosition
+ */
+size_t parcBuffer_Position(const PARCBuffer *buffer);
+
+/**
+ * Set the given `PARCBuffer`'s position.
+ *
+ * A buffer's position is the index of the next element to be read or written.
+ * A buffer's position is never negative and is never greater than its limit.
+ *
+ * If the mark is defined and larger than the new position then the mark
+ * is invalidated and any subsequent operation on the resulting
+ * `PARCBuffer` that requires the mark will abort until the mark
+ * is set again via `parcBuffer_Mark`.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ * @param [in] newPosition The buffer's new position which must be less than or equal to the current limit.
+ *
+ * @return The given `PARCBuffer`'s position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_SetPosition(buffer, 5);
+ * parcBuffer_Remaining(buffer); // Returns 5.
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Limit
+ */
+PARCBuffer *parcBuffer_SetPosition(PARCBuffer *buffer, size_t newPosition);
+
+/**
+ * Returns the number of elements between the current position and the limit.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The number of elements remaining in this `PARCBuffer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_SetPosition(buffer, 5);
+ * parcBuffer_Remaining(buffer); // Returns 5.
+ * }
+ * @endcode
+ */
+size_t parcBuffer_Remaining(const PARCBuffer *buffer);
+
+/**
+ * Tells whether there are any elements between the current position and the limit.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return true The `PARCBuffer` contains at least one more element.
+ * @return false The `PARCBuffer` does not contain any more elements.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_SetPosition(buffer, 5);
+ * bool hasRemaining = parcBuffer_HasRemaining(buffer); // returns true since #remaining = 5
+ * }
+ * @endcode
+ */
+bool parcBuffer_HasRemaining(const PARCBuffer *buffer);
+
+/**
+ * Creates a new byte buffer whose content is a shared subsequence of this buffer's content.
+ *
+ * The content of the new buffer will start at this buffer's current position.
+ * Changes to this buffer's content will be visible in the new buffer,
+ * and vice versa;
+ * the two buffers' position, limit,
+ * and mark values will be independent.
+ *
+ * The new buffer's position will be zero,
+ * its capacity and its limit will be the number of bytes remaining in this buffer,
+ * and its mark will be undefined.
+ *
+ * @param [in] original A pointer to a `PARCBuffer` instance.
+ *
+ * @return non-NULL A pointer to a new `PARCBuffer` whose content is a shared subsequence of the original buffer's content.
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_SetPosition(buffer, 5);
+ * parcBuffer_SetLimit(buffer, 8);
+ *
+ * PARCBuffer *slice = parcBuffer_Slice(buffer);
+ * // the slice will be the subset of bytes 5,6,7, and will
+ * // have limit and capacity of 3 (= 8 - 5)
+ *
+ * ...
+ *
+ * parcBuffer_Release(&buffer);
+ * parcBuffer_Release(&slice);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Slice(const PARCBuffer *original);
+
+/**
+ * Set the limit to the current position,
+ * then set the position to zero.
+ * If the mark is defined, it is invalidated.
+ *
+ * Any subsequent operation that requires the mark will abort until the mark
+ * is set again via `parcBuffer_Mark`.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The same value as @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutByte(buffer, 'X');
+ * parcBuffer_Flip(buffer);
+ * uint8_t actual = parcBuffer_GetUint8(buffer);
+ *
+ * ...
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_Flip(PARCBuffer *buffer);
+
+/**
+ * Get the single `uint8_t` at the index specified.
+ *
+ * The buffer's position is not modified.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ * @param [in] index The index into the @p buffer to find the `uint8_t`.
+ *
+ * @return The `uint8_t` value at @p index.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutByte(buffer, 'X');
+ * uint8_t actual = parcBuffer_GetAtIndex(buffer, 0);
+ * // actual == (uint8_t) 'X'
+ *
+ * ...
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+uint8_t parcBuffer_GetAtIndex(const PARCBuffer *buffer, size_t index);
+
+/**
+ * Read the unsigned 8-bit value at the buffer's current position,
+ * and then increment the position by 1.
+ *
+ * @param [in] buffer The pointer to a `PARCBuffer` instance containing the `uint8_t` value.
+ *
+ * @return The `uint8_t` at the buffer's current position
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutByte(buffer, 'X');
+ * parcBuffer_Flip(buffer);
+ * uint8_t actual = parcBuffer_GetUint8(buffer);
+ *
+ * ...
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ */
+uint8_t parcBuffer_GetUint8(PARCBuffer *buffer);
+
+/**
+ * Read the unsigned 16-bit value in network order at the buffer's current position,
+ * and then increment the position by 2.
+ *
+ * @param [in,out] buffer The pointer to the `PARCBuffer` instance containing the value.
+ *
+ * @return The `uint16_t` at the buffer's current position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * (buffer, 0x1234);
+ * parcBuffer_Flip(buffer);
+ * uint16_t actual = parcBuffer_GetUint16(buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Overlay
+ */
+uint16_t parcBuffer_GetUint16(PARCBuffer *buffer);
+
+/**
+ * Read the unsigned 32-bit value in network order at the buffer's current position,
+ * and then increment the position by the 4.
+ *
+ * @param [in,out] buffer The pointer to the instance of `PARCBuffer` containing the value.
+ *
+ * @return The `uint32_t` at the buffer's current position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint32(buffer, 0x12345678);
+ * parcBuffer_Flip(buffer);
+ * uint32_t actual = parcBuffer_GetUint32(buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Overlay
+ */
+uint32_t parcBuffer_GetUint32(PARCBuffer *buffer);
+
+/**
+ * Read the unsigned 64-bit value in network order at the buffer's current position,
+ * and then increment the position by 8.
+ *
+ * @param [in,out] buffer The pointer to the instance of `PARCBuffer` containing the value.
+ *
+ * @return The `uint64_t` at the buffer's current position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint64(buffer, 0x12345678);
+ * parcBuffer_Flip(buffer);
+ * uint64_t actual = parcBuffer_GetUint64(buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Overlay
+ */
+uint64_t parcBuffer_GetUint64(PARCBuffer *buffer);
+
+/**
+ * Read an array of length bytes from the given PARCBuffer, copying them to an array.
+ *
+ * The buffer's position is incremented by @p length.
+ *
+ * @param [in,out] buffer The pointer to the instance of `PARCBuffer` containing the `uint8_t` value.
+ * @param [in] length The number of `uint8_t` elements to get.
+ * @param [in] array The `uint8_t` array to receive @p length bytes.
+ *
+ * @return A pointer to the given `PARCBuffer` instance
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(5);
+ * parcBuffer_PutUint8(buffer, 'A');
+ * parcBuffer_PutUint8(buffer, 'B');
+ * parcBuffer_PutUint8(buffer, 'C');
+ *
+ * uint8_t array[3];
+ * parcBuffer_GetBytes(buffer, 3, array);
+ * // array[0] == 'A'
+ * // array[1] == 'B'
+ * // array[2] == 'C'
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Overlay
+ */
+PARCBuffer *parcBuffer_GetBytes(PARCBuffer *buffer, size_t length, uint8_t *array);
+
+/**
+ * Insert an unsigned 8-bit value into the given `PARCBuffer` at the current position.
+ *
+ * Advance the current position by 1.
+ *
+ * @param [in,out] buffer A pointer to the `PARCBuffer` instance.
+ * @param [in] value The value to be inserted into the`PARCBuffer` instance at the current position.
+ * @return The `PARCBuffer`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutByte(buffer, 'X');
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_PutUint8(PARCBuffer *buffer, uint8_t value);
+
+/**
+ * Insert an unsigned 16-bit value into the given `PARCBuffer` at the current position,
+ * in big-endian, network-byte-order.
+ *
+ * Advance the current position by 2.
+ *
+ * @param [in,out] buffer A pointer to the `PARCBuffer` instance.
+ * @param [in] value The value to be inserted
+ * @return The pointer to `PARCBuffer`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint16(buffer, 0x1234);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_PutUint16(PARCBuffer *buffer, uint16_t value);
+
+/**
+ * Insert an unsigned 32-bit value into the given `PARCBuffer` at the current position,
+ * in big-endian, network-byte-order.
+ *
+ * Advance the current position by 4.
+ *
+ * @param [in,out] buffer A pointer to the `PARCBuffer` instance.
+ * @param [in] value The value to be inserted
+ * @return The `PARCBuffer`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint32(buffer, 0x12345678);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_PutUint32(PARCBuffer *buffer, uint32_t value);
+
+/**
+ * Insert an unsigned 64-bit value into the given `PARCBuffer` at the current position,
+ * in big-endian, network-byte-order.
+ *
+ * Advance the current position by 8.
+ *
+ * @param [in,out] buffer A pointer to the `PARCBuffer` instance.
+ * @param [in] value The value to be inserted
+ * @return The `PARCBuffer`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint64(buffer, 0x1234);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_PutUint64(PARCBuffer *buffer, uint64_t value);
+
+/**
+ * Insert unsigned 8-bit value to the given `PARCBuffer` at given index.
+ *
+ * The buffer's position is unchanged.
+ *
+ * @param [in,out] buffer A pointer to the `PARCBuffer` instance.
+ * @param [in] index The index at which to insert @p value
+ * @param [in] value The value to be inserted
+ *
+ * @return The value of @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutAtIndex(buffer, 3, 'X');
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_PutAtIndex(PARCBuffer *buffer, size_t index, uint8_t value);
+
+/**
+ * Copy `arrayLength` bytes from the given array into the `PARCBuffer`.
+ *
+ * The position is incremented by `arrayLength`
+ *
+ * @param [in] buffer A pointer to the `PARCBuffer` instance.
+ * @param [in] arrayLength The number of bytes to copy into the buffer.
+ * @param [in] array A pointer to the array of bytes.
+ *
+ * @return The value of @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(5);
+ *
+ * uint8_t array[3];
+ * array[0] = 'A';
+ * array[1] = 'B';
+ * array[2] = 'C';
+ *
+ * parcBuffer_PutArray(buffer, 3, array);
+ * // the buffer will now contain ['A','B','C'] at indices 0,1,2
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_PutArray(PARCBuffer *buffer, size_t arrayLength, const uint8_t *array);
+
+/**
+ * Copy the contents of the given nul-terminated C string into a PARCBuffer, including the terminating nul byte.
+ *
+ * The position is incremented by the length of the string plus 1.
+ *
+ * @param [in] buffer A pointer to the `PARCBuffer` instance.
+ * @param [in] string A pointer to nul-terminated C string.
+ *
+ * @return The value of @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(5);
+ *
+ * char *string = "ABC";
+ *
+ * parcBuffer_PutCString(buffer, string);
+ * // the buffer will now contain ['A','B','C', 0] at indices 0, 1, 2, and 3
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_PutCString(PARCBuffer *buffer, const char *string);
+
+/**
+ * Put the contents of a `PARCBuffer` into another.
+ *
+ * @param [in] buffer A pointer to the destination `PARCBuffer` instance.
+ * @param [in] source A pointer to the source `PARCBuffer` instance.
+ *
+ * @return The value of @p result.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * PARCBuffer *insertee = parcBuffer_AllocateCString("Hello");
+ * parcBuffer_PutBuffer(buffer, insertee);
+ * // buffer will now contain "Hello" in the first 5 byte indices
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBuffer_PutBuffer(PARCBuffer *buffer, const PARCBuffer *source);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The hash code of a `PARCBuffer` depends only upon its remaining elements from the current position to the limit.
+ *
+ * Because `PARCBuffer` hash codes are content-dependent, be careful when using them as keys in `PARCHashMap`
+ * and other similar data structures unless it is known that their contents will not change.
+ *
+ * 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 {@link parcByteArray_Equals}
+ * 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 parcByteArray_Equals} method,
+ * then calling the {@link parcBuffer_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 parcBuffer_Equals} function,
+ * then calling the `parcBuffer_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] buffer A pointer to the `PARCBuffer` instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * uint32_t hashValue = parcBuffer_HashCode(buffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcByteArray_HashCode
+ */
+PARCHashCode parcBuffer_HashCode(const PARCBuffer *buffer);
+
+/**
+ * Return the position of the first `uint8_t` value that matches the given byte.
+ *
+ * If the value does not exist between the current position and the limit,
+ * return `SIZE_MAX` (<stdint.h>).
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ * @param [in] byte The byte to search for within the buffer.
+ *
+ * @return The index of the first byte equal to `byte`, or `SIZE_MAX` (<stdint.h>)
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap("Hello World", 10, 0, 10);
+ *
+ * size_t ePosition = parcBuffer_FindUint8(buffer, 'e');
+ *
+ * // ePosition is equal to 1.
+ *
+ * size_t xPosition = parcBuffer_FindUint8(buffer, 'x');
+ *
+ * // ePosition is equal to SIZE_MAX.
+ * }
+ * @endcode
+ */
+size_t parcBuffer_FindUint8(const PARCBuffer *buffer, uint8_t byte);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCBuffer`
+ * from the current position to the limit.
+ * The buffer's position is not changed.
+ *
+ * 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, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * char *helloWorld = "Hello World";
+ * PARCBuffer *instance = parcBuffer_Wrap(helloWorld, strlen(helloWorld), 0, strlen(helloWorld));
+ *
+ * char *string = parcBuffer_ToString(instance);
+ *
+ * if (string != NULL) {
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * parcBuffer_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_Display
+ */
+char *parcBuffer_ToString(const PARCBuffer *buffer);
+
+/**
+ * Print a human readable representation of the given `PARCBuffer`.
+ *
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ * @param [in] buffer A pointer to the instance to display.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *instance = parcBuffer_Create();
+ *
+ * parcBuffer_Display(instance, 0);
+ *
+ * parcBuffer_Release(&instance);
+ * }
+ * @endcode
+ */
+void parcBuffer_Display(const PARCBuffer *buffer, int indentation);
+
+/**
+ * Return a null-terminated string containing the hex-byte representation of the given `PARCBuffer`.
+ *
+ * The result must be freed by the caller via `parcMemory_Deallocate()`.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` 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
+ * {
+ * PARCBuffer *instance = parcBuffer_Create();
+ *
+ * char *hexString = parcBuffer_ToHexString(instance);
+ * parcMemory_Deallocate((void **)&hexString);
+ *
+ * parcBuffer_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see parcMemory_Deallocate
+ */
+char *parcBuffer_ToHexString(const PARCBuffer *buffer);
+
+/**
+ * Advance the position of the given buffer to the first byte that is not in the array @p bytesToSkipOver.
+ *
+ * The position will not exceed the PARCBuffer's limit.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ * @param [in] length Length of the byte array that includes skip bytes
+ * @param [in] bytesToSkipOver A null-terminated array of bytes to skip.
+ *
+ * @return true The `PARCBuffer`'s position was updated.
+ * @return false The `PARCBuffer`'s position reached the limit.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ * uint8_t skipOverBytes[] = { 'H', 0 };
+ *
+ * bool actual = parcBuffer_SkipOver(buffer, 1, skipOverBytes);
+ * // the buffer position will now be 1, as it skipped over the 'H' byte in the array
+ * // actual will be true
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_SkipTo
+ */
+bool parcBuffer_SkipOver(PARCBuffer *buffer, size_t length, const uint8_t *bytesToSkipOver);
+
+/**
+ * Advance the position of the given buffer to the first byte that is in the array @p bytesToSkipTo.
+ *
+ * The position will not exceed the PARCBuffer's limit.
+ *
+ * @param [in,out] buffer A pointer to a `PARCBuffer` instance.
+ * @param [in] length Length of the byte array that includes skip bytes
+ * @param [in] bytesToSkipTo A null-terminated array of bytes to find.
+ *
+ * @return true The PARCBuffer's position is at the first byte matched.
+ * @return false The PARCBuffer's position reached the limit.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ * uint8_t skipOverBytes[] = { 'l', 0 };
+ *
+ * bool actual = parcBuffer_SkipTo(buffer, 1, skipOverBytes);
+ * // the buffer position will now be set to the index of the first 'l' byte in the underlying array
+ * // actual will be true
+ * }
+ * @endcode
+ *
+ * @see parcBuffer_SkipOver
+ */
+bool parcBuffer_SkipTo(PARCBuffer *buffer, size_t length, const uint8_t *bytesToSkipTo);
+
+/**
+ * Return the byte at the given `PARCBuffers'` current position, without modifying the position.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The byte at the given `PARCBuffers'` current position
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_AllocateCString("Hello");
+ * uint8_t byte = parcBuffer_PeekByte(1);
+ * // byte == (uint8_t) 'e';
+ * }
+ * @endcode
+ */
+uint8_t parcBuffer_PeekByte(const PARCBuffer *buffer);
+
+/**
+ * Parse an ASCII representation of a hexadecimal number in the given `PARCBuffer`
+ *
+ * The number may be prefixed with the characters '0', 'x'.
+ * The buffer's position will be left at the first non-parsable character.
+ *
+ * Overflow is not checked.
+ *
+ * @param [in] buffer A pointer to a valid `PARCBuffer` instance.
+ *
+ * @return A uint64_t of the hexadecimal number.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("0x10");
+ * uint64_t value = parcBuffer_ParseHexNumber(buffer);
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+uint64_t parcBuffer_ParseHexNumber(PARCBuffer *buffer);
+
+/**
+ * Parse an ASCII representation of a unsigned decimal number in the given `PARCBuffer`
+ *
+ * The buffer's position will be left at the first non-parsable character.
+ *
+ * Overflow is not checked.
+ *
+ * @param [in] buffer A pointer to a valid `PARCBuffer` instance.
+ *
+ * @return A uint64_t of the decimal number.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("100");
+ * uint64_t value = parcBuffer_ParseDecimalNumber(buffer);
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+uint64_t parcBuffer_ParseDecimalNumber(PARCBuffer *buffer);
+
+/**
+ * Parse an ASCII representation of a unsigned decimal number or a hexadecimal number in the given `PARCBuffer`
+ *
+ * The buffer's position will be left at the first non-parsable character.
+ *
+ * Overflow is not checked.
+ *
+ * @param [in] buffer A pointer to a valid `PARCBuffer` instance.
+ *
+ * @return A uint64_t of the number.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("100");
+ * uint64_t value = parcBuffer_ParseNumeric(buffer);
+ *
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+uint64_t parcBuffer_ParseNumeric(PARCBuffer *buffer);
+#endif // libparc_parc_Buffer_h
diff --git a/libparc/parc/algol/parc_BufferChunker.c b/libparc/parc/algol/parc_BufferChunker.c
new file mode 100644
index 00000000..f3a4ab67
--- /dev/null
+++ b/libparc/parc/algol/parc_BufferChunker.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 <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_BufferChunker.h>
+
+PARCChunkerInterface *PARCBufferChunkerAsChunker = &(PARCChunkerInterface) {
+ .ForwardIterator = (void *(*)(const void *))parcBufferChunker_ForwardIterator,
+ .ReverseIterator = (void *(*)(const void *))parcBufferChunker_ReverseIterator,
+ .GetChunkSize = (size_t (*)(const void *))parcBufferChunker_GetChunkSize
+};
+
+struct _parc_chunker_state {
+ size_t chunkNumber;
+ int direction;
+ bool atEnd;
+ size_t position;
+ size_t nextChunkSize;
+};
+
+typedef struct _parc_chunker_state _ChunkerState;
+
+struct parc_buffer_chunker {
+ // State
+ size_t chunkSize;
+
+ // Container for the data to be parsed
+ PARCBuffer *data;
+
+ // The current element of the iterator
+ PARCBuffer *currentElement;
+};
+
+static void
+_destroy(PARCBufferChunker **chunkerP)
+{
+ if ((*chunkerP)->data != NULL) {
+ parcBuffer_Release(&(*chunkerP)->data);
+ }
+
+ if ((*chunkerP)->currentElement != NULL) {
+ parcBuffer_Release(&(*chunkerP)->currentElement);
+ }
+}
+
+static void *
+_InitForward(PARCBufferChunker *chunker)
+{
+ _ChunkerState *state = parcMemory_Allocate(sizeof(_ChunkerState));
+
+ state->chunkNumber = 0;
+ state->direction = 0;
+ state->position = 0;
+ state->atEnd = false;
+
+ if (parcBuffer_Remaining(chunker->data) < chunker->chunkSize) {
+ state->nextChunkSize = parcBuffer_Remaining(chunker->data);
+ } else {
+ state->nextChunkSize = chunker->chunkSize;
+ }
+
+ return state;
+}
+
+static void *
+_InitReverse(PARCBufferChunker *chunker)
+{
+ _ChunkerState *state = parcMemory_Allocate(sizeof(_ChunkerState));
+
+ state->chunkNumber = 0;
+ state->direction = 1;
+ state->atEnd = false;
+
+ if (parcBuffer_Remaining(chunker->data) < chunker->chunkSize) {
+ state->position = 0;
+ state->nextChunkSize = parcBuffer_Remaining(chunker->data);
+ } else {
+ state->position = parcBuffer_Remaining(chunker->data) - chunker->chunkSize;
+ state->nextChunkSize = chunker->chunkSize;
+ }
+
+ return state;
+}
+
+static bool
+_ccnxChunker_HasNext(PARCBufferChunker *chunker, void *voidstate)
+{
+ _ChunkerState *state = (_ChunkerState *) voidstate;
+ return !state->atEnd;
+}
+
+static void
+_advanceStateForward(PARCBufferChunker *chunker, _ChunkerState *state)
+{
+ state->position += state->nextChunkSize;
+
+ size_t remaining = parcBuffer_Remaining(chunker->data);
+
+ if (remaining == 0) {
+ state->atEnd = true;
+ } else if (remaining > chunker->chunkSize) {
+ state->nextChunkSize = chunker->chunkSize;
+ } else {
+ state->nextChunkSize = remaining;
+ }
+}
+
+static void
+_advanceStateBackward(PARCBufferChunker *chunker, _ChunkerState *state)
+{
+ // Previous chunk size
+ size_t chunkSize = state->nextChunkSize;
+ if (chunkSize != chunker->chunkSize || state->position == 0) {
+ state->atEnd = true;
+ } else {
+ if (state->position < chunkSize) {
+ state->nextChunkSize = state->position; // on next read, go to the current position
+ state->position = 0; // we reached the beginning
+ } else {
+ state->position -= chunkSize;
+ }
+ }
+}
+
+static void
+_advanceState(PARCBufferChunker *chunker, _ChunkerState *state)
+{
+ state->chunkNumber++;
+
+ if (state->direction == 0) {
+ _advanceStateForward(chunker, state);
+ } else {
+ _advanceStateBackward(chunker, state);
+ }
+}
+
+static void *
+_ccnxChunker_NextFromBuffer(PARCBufferChunker *chunker, _ChunkerState *state)
+{
+ size_t chunkSize = state->nextChunkSize;
+
+ parcBuffer_SetPosition(chunker->data, state->position);
+ PARCBuffer *slice = parcBuffer_CreateFromArray(parcBuffer_Overlay(chunker->data, chunkSize), chunkSize);
+ slice = parcBuffer_Flip(slice);
+
+ _advanceState(chunker, state);
+
+ return slice;
+}
+
+static void *
+_ccnxChunker_Next(PARCBufferChunker *chunker, void *state)
+{
+ PARCBuffer *buffer = _ccnxChunker_NextFromBuffer(chunker, state);
+
+ if (chunker->currentElement != NULL) {
+ parcBuffer_Release(&chunker->currentElement);
+ }
+ if (buffer != NULL) {
+ chunker->currentElement = parcBuffer_Acquire(buffer);
+ }
+
+ return state;
+}
+
+static void *
+_ccnxChunker_GetElement(PARCBufferChunker *chunker, void *state)
+{
+ return chunker->currentElement;
+}
+
+static void
+_ccnxChunker_Finish(PARCBufferChunker *chunker, void *state)
+{
+ _ChunkerState *thestate = (_ChunkerState *) state;
+ parcMemory_Deallocate(&thestate);
+}
+
+static void
+_ccnxChunker_AssertValid(const void *state)
+{
+ // pass
+}
+
+parcObject_ExtendPARCObject(PARCBufferChunker, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+parcObject_ImplementAcquire(parcBufferChunker, PARCBufferChunker);
+parcObject_ImplementRelease(parcBufferChunker, PARCBufferChunker);
+
+PARCBufferChunker *
+parcBufferChunker_Create(PARCBuffer *data, size_t chunkSize)
+{
+ PARCBufferChunker *chunker = parcObject_CreateInstance(PARCBufferChunker);
+
+ if (chunker != NULL) {
+ chunker->chunkSize = chunkSize;
+ chunker->data = parcBuffer_Acquire(data);
+ chunker->currentElement = NULL;
+ }
+
+ return chunker;
+}
+
+PARCIterator *
+parcBufferChunker_ForwardIterator(const PARCBufferChunker *chunker)
+{
+ PARCIterator *iterator = parcIterator_Create((void *) chunker,
+ (void *(*)(PARCObject *))_InitForward,
+ (bool (*)(PARCObject *, void *))_ccnxChunker_HasNext,
+ (void *(*)(PARCObject *, void *))_ccnxChunker_Next,
+ NULL,
+ (void *(*)(PARCObject *, void *))_ccnxChunker_GetElement,
+ (void (*)(PARCObject *, void *))_ccnxChunker_Finish,
+ (void (*)(const void *))_ccnxChunker_AssertValid);
+
+ return iterator;
+}
+
+PARCIterator *
+parcBufferChunker_ReverseIterator(const PARCBufferChunker *chunker)
+{
+ PARCIterator *iterator = parcIterator_Create((void *) chunker,
+ (void *(*)(PARCObject *))_InitReverse,
+ (bool (*)(PARCObject *, void *))_ccnxChunker_HasNext,
+ (void *(*)(PARCObject *, void *))_ccnxChunker_Next,
+ NULL,
+ (void *(*)(PARCObject *, void *))_ccnxChunker_GetElement,
+ (void (*)(PARCObject *, void *))_ccnxChunker_Finish,
+ (void (*)(const void *))_ccnxChunker_AssertValid);
+
+ return iterator;
+}
+
+size_t
+parcBufferChunker_GetChunkSize(const PARCBufferChunker *chunker)
+{
+ return chunker->chunkSize;
+}
diff --git a/libparc/parc/algol/parc_BufferChunker.h b/libparc/parc/algol/parc_BufferChunker.h
new file mode 100755
index 00000000..16f21c49
--- /dev/null
+++ b/libparc/parc/algol/parc_BufferChunker.h
@@ -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.
+ */
+
+/**
+ * @file parc_BufferChunker.h
+ * @ingroup ContentObject
+ * @brief A BufferChunker is a chunker that segments a PARCBuffer.
+ *
+ */
+
+#ifndef libparc_parc_BufferChunker_h
+#define libparc_parc_BufferChunker_h
+
+#include <parc/algol/parc_Chunker.h>
+
+struct parc_buffer_chunker;
+/**
+ * @typedef PARCChunker
+ * @brief The PARC Chunker
+ */
+typedef struct parc_buffer_chunker PARCBufferChunker;
+
+/**
+ * The mapping of a `PARCBufferChunker` to the generic `PARCChunker`.
+ */
+extern PARCChunkerInterface *PARCBufferChunkerAsChunker;
+
+/**
+ * Create a new chunker to segment data contained in a `PARCBuffer.`
+ *
+ * @param [in] data A `PARCBuffer` which contains the data.
+ * @param [in] chunkSize The size per chunk.
+ *
+ * @retval PARCChunker A newly allocated `PARCChunker`
+ * @retval NULL An error occurred.
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCChunker *chunker = ccnxChunker_CreateFromBuffer(dataToChunk, 32);
+ * }
+ */
+PARCBufferChunker *parcBufferChunker_Create(PARCBuffer *data, size_t chunkSize);
+
+/**
+ * Increase the number of references to a `PARCChunker` instance.
+ *
+ * Note that new `PARCChunker` is not created,
+ * only that the given `PARCChunker` reference count is incremented.
+ * Discard the reference by invoking {@link ccnxChunker_Release}.
+ *
+ * @param [in] chunker A pointer to the original `PARCChunker`.
+ * @return The value of the input parameter @p chunker.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferChunker *original = parcBufferChunker_Create(...);
+ *
+ * PARCBufferChunker *reference = parcBufferChunker_Acquire(original);
+ *
+ * parcBufferChunker_Release(&original);
+ * parcBufferChunker_Release(&reference);
+ * }
+ * @endcode
+ *
+ * @see parcBufferChunker_Release
+ */
+PARCBufferChunker *parcBufferChunker_Acquire(const PARCBufferChunker *chunker);
+
+/**
+ * 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] chunkerP A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCBufferChunker *chunker = parcBufferChunker_Acquire(instance);
+ *
+ * parcBufferChunker_Release(&chunker);
+ * }
+ * @endcode
+ */
+void parcBufferChunker_Release(PARCBufferChunker **chunkerP);
+
+/**
+ * Determine if two `PARCBufferChunker` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCBufferChunker` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcBufferChunker_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcBufferChunker_Equals(x, y)` must return true if and only if
+ * `parcBufferChunker_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcBufferChunker_Equals(x, y)` returns true and
+ * `parcBufferChunker_Equals(y, z)` returns true,
+ * then `parcBufferChunker_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcBufferChunker_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcBufferChunker_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param chunkerA A pointer to a `PARCBufferChunker` instance.
+ * @param chunkerB A pointer to a `PARCBufferChunker` instance.
+ * @return true if the two `PARCBufferChunker` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCBufferChunker *chunkerA = parcBufferChunker_Create(dataToChunk, 32);
+ * PARCBufferChunker *chunkerB = parcBufferChunker_Create(dataToChunk, 32);
+ *
+ * bool equals = parcBufferChunker_Equals(chunkerA, chunkerB);
+ * }
+ * @endcode
+ */
+bool parcBufferChunker_Equals(const PARCBufferChunker *chunkerA, const PARCBufferChunker *chunkerB);
+
+/**
+ * Return an iterator to traverse the chunks of the underlying data in sequential order.
+ *
+ * This function can only be called once per chunker instance since the iterator
+ * will mutate internal state of the chunker.
+ *
+ * @param [in] chunker A `PARCBufferChunker` instance.
+ *
+ * @return a `PARCIterator` that traverses the chunks of the underlying data.
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCBufferChunker *chunker = parcBufferChunker_Create(dataToChunk, 32);
+ *
+ * PARCIterator *itr = parcBufferChunker_ForwardIterator(chunker);
+ *
+ * // use the iterator to traverse the chunker
+ * }
+ * @endcode
+ */
+PARCIterator *parcBufferChunker_ForwardIterator(const PARCBufferChunker *chunker);
+
+/**
+ * Return an iterator to traverse the chunks of the underlying data in sequential order.
+ *
+ * This function can only be called once per chunker instance since the iterator
+ * will mutate internal state of the chunker.
+ *
+ * @param [in] chunker A `PARCBufferChunker` instance.
+ *
+ * @return a `PARCIterator` that traverses the chunks of the underlying data.
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCBufferChunker *chunker = parcBufferChunker_Create(dataToChunk, 32);
+ *
+ * PARCIterator *itr = parcBufferChunker_ReverseIterator(chunker);
+ *
+ * // use the iterator to traverse the chunker
+ * }
+ * @endcode
+ */
+PARCIterator *parcBufferChunker_ReverseIterator(const PARCBufferChunker *chunker);
+
+/**
+ * Get the chunk size of a `PARCBufferChunker.`
+ *
+ * @param [in] chunker A `PARCBufferChunker` instance.
+ *
+ * @return the chunk size
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCBufferChunker *chunker = ...
+ *
+ * size_t chunkSize = parcBufferChunker_GetChunkSize(chunker);
+ * }
+ * @endcode
+ */
+size_t parcBufferChunker_GetChunkSize(const PARCBufferChunker *chunker);
+#endif // libparc_parc_BufferChunker_h
diff --git a/libparc/parc/algol/parc_BufferComposer.c b/libparc/parc/algol/parc_BufferComposer.c
new file mode 100755
index 00000000..20b7ecee
--- /dev/null
+++ b/libparc/parc/algol/parc_BufferComposer.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 <LongBow/runtime.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Buffer.h>
+
+struct parc_buffer_composer {
+ size_t incrementHeuristic;
+ PARCBuffer *buffer;
+};
+
+static void
+_finalize(PARCBufferComposer **bufferPtr)
+{
+ if (bufferPtr != NULL) {
+ PARCBufferComposer *composer = *bufferPtr;
+ parcBufferComposer_OptionalAssertValid(composer);
+ if (composer->buffer != NULL) {
+ parcBuffer_Release(&composer->buffer);
+ }
+ }
+}
+
+parcObject_ExtendPARCObject(PARCBufferComposer, _finalize, NULL, NULL, parcBufferComposer_Equals, NULL, NULL, NULL);
+
+static PARCBufferComposer *
+_create(void)
+{
+ return parcObject_CreateInstance(PARCBufferComposer);
+}
+
+/**
+ * Ensure that the given `PARCBufferComposer` has at least the required number of bytes remaining.
+ *
+ * If the remaining capacity (the difference between the capacity of the buffer and its current position)
+ * of the underlying `PARCBuffer` is less than the required number of bytes,
+ * the underlying PARCBuffer is expanded with sufficient space to accomodate the required number of bytes.
+ *
+ * The position, limit, and mark remain unchanged.
+ * The capacity is increased.
+ */
+static PARCBufferComposer *
+_ensureRemaining(PARCBufferComposer *composer, size_t required)
+{
+ parcBufferComposer_OptionalAssertValid(composer);
+
+ size_t remainingCapacity = parcBuffer_Capacity(composer->buffer) - parcBuffer_Position(composer->buffer);
+
+ if (remainingCapacity < required) {
+ size_t incrementAmount = required;
+ if (incrementAmount < composer->incrementHeuristic) {
+ incrementAmount = composer->incrementHeuristic;
+ }
+ size_t newCapacity = parcBuffer_Capacity(composer->buffer) + incrementAmount;
+
+ PARCBuffer *newBuffer = parcBuffer_Allocate(newCapacity);
+ parcBuffer_Flip(composer->buffer);
+ parcBuffer_PutBuffer(newBuffer, composer->buffer);
+ parcBuffer_Release(&composer->buffer);
+ composer->buffer = newBuffer;
+ }
+
+ return composer;
+}
+
+void
+parcBufferComposer_AssertValid(const PARCBufferComposer *composer)
+{
+ trapIllegalValueIf(composer == NULL, "Parameter must be a non-null pointer to a valid PARCBufferComposer.");
+ trapIllegalValueIf(composer->incrementHeuristic < sizeof(void *), "Heuristic cannot be < sizeof(void *) (%zd), actual %zd", sizeof(void *), composer->incrementHeuristic);
+}
+
+PARCBufferComposer *
+parcBufferComposer_Create(void)
+{
+ return parcBufferComposer_Allocate(parcMemory_RoundUpToCacheLine(LEVEL1_DCACHE_LINESIZE));
+}
+
+PARCBufferComposer *
+parcBufferComposer_Allocate(size_t size)
+{
+ PARCBufferComposer *result = _create();
+ if (result != NULL) {
+ result->buffer = parcBuffer_Allocate(size);
+ result->incrementHeuristic = parcMemory_RoundUpToCacheLine(size);
+ if (result->buffer == NULL) {
+ result->incrementHeuristic = sizeof(void *); // minimum size
+ parcBufferComposer_Release(&result);
+ }
+ }
+ return result;
+}
+
+parcObject_ImplementAcquire(parcBufferComposer, PARCBufferComposer);
+
+parcObject_ImplementRelease(parcBufferComposer, PARCBufferComposer);
+
+bool
+parcBufferComposer_Equals(const PARCBufferComposer *x, const PARCBufferComposer *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ if (x->incrementHeuristic == y->incrementHeuristic) {
+ if (parcBuffer_Equals(x->buffer, y->buffer)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutArray(PARCBufferComposer *composer, const unsigned char *bytes, size_t length)
+{
+ if (length > 0) {
+ composer = _ensureRemaining(composer, length);
+ if (composer != NULL) {
+ parcBuffer_PutArray(composer->buffer, length, bytes);
+ }
+ }
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutChar(PARCBufferComposer *composer, char val)
+{
+ return parcBufferComposer_PutUint8(composer, (uint8_t) val);
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutUint8(PARCBufferComposer *composer, uint8_t byte)
+{
+ composer = _ensureRemaining(composer, 1);
+ if (composer != NULL) {
+ parcBuffer_PutUint8(composer->buffer, byte);
+ }
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutUint16(PARCBufferComposer *composer, uint16_t value)
+{
+ composer = _ensureRemaining(composer, 2);
+ if (composer != NULL) {
+ parcBuffer_PutUint16(composer->buffer, value);
+ }
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutUint32(PARCBufferComposer *composer, uint32_t value)
+{
+ composer = _ensureRemaining(composer, 4);
+ if (composer != NULL) {
+ parcBuffer_PutUint32(composer->buffer, value);
+ }
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutUint64(PARCBufferComposer *composer, uint64_t value)
+{
+ composer = _ensureRemaining(composer, 8);
+ if (composer != NULL) {
+ parcBuffer_PutUint64(composer->buffer, value);
+ }
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutBuffer(PARCBufferComposer *composer, const PARCBuffer *source)
+{
+ composer = _ensureRemaining(composer, parcBuffer_Remaining(source));
+ if (composer != NULL) {
+ parcBuffer_PutBuffer(composer->buffer, source);
+ }
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutString(PARCBufferComposer *composer, const char *string)
+{
+ PARCBuffer *wrapper = parcBuffer_AllocateCString(string);
+
+ composer = _ensureRemaining(composer, parcBuffer_Remaining(wrapper));
+ if (composer != NULL) {
+ parcBuffer_PutBuffer(composer->buffer, wrapper);
+ }
+
+ parcBuffer_Release(&wrapper);
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcBufferComposer_PutStrings(PARCBufferComposer *composer, ...)
+{
+ va_list ap;
+ va_start(ap, composer);
+
+ char *arg;
+ while ((arg = va_arg(ap, char *)) != NULL) {
+ parcBufferComposer_PutString(composer, arg);
+ }
+ va_end(ap);
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcBufferComposer_Format(PARCBufferComposer *composer, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ char *cString;
+ ssize_t written = vasprintf(&cString, format, ap);
+ assertTrue(written >= 0, "Got error from vasprintf");
+ va_end(ap);
+
+ parcBufferComposer_PutString(composer, cString);
+ free(cString);
+
+ return composer;
+}
+
+PARCBuffer *
+parcBufferComposer_GetBuffer(const PARCBufferComposer *composer)
+{
+ return composer->buffer;
+}
+
+PARCBuffer *
+parcBufferComposer_CreateBuffer(PARCBufferComposer *composer)
+{
+ return parcBuffer_Duplicate(composer->buffer);
+}
+
+PARCBuffer *
+parcBufferComposer_ProduceBuffer(PARCBufferComposer *composer)
+{
+ return parcBuffer_Acquire(parcBuffer_Flip(composer->buffer));
+}
+
+char *
+parcBufferComposer_ToString(PARCBufferComposer *composer)
+{
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_Duplicate(composer->buffer));
+
+ char *result = parcBuffer_ToString(buffer);
+ parcBuffer_Release(&buffer);
+
+ return result;
+}
diff --git a/libparc/parc/algol/parc_BufferComposer.h b/libparc/parc/algol/parc_BufferComposer.h
new file mode 100755
index 00000000..f45aeb8e
--- /dev/null
+++ b/libparc/parc/algol/parc_BufferComposer.h
@@ -0,0 +1,571 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_BufferComposer.h
+ * @ingroup memory
+ * @brief An elastic memory composer of PARCBuffer instances.
+ *
+ * A `PARCBufferComposer` is a dynamically allocated buffer that can be used to incrementally add (append)
+ * intrinsic values and/or `PARCBuffer` instance contents to a single location. It is meant to be a general
+ * purpose buffer in that all native types may be added to the buffer. When finished, the user can finalize
+ * the composer and produce a flipped `PARCBuffer` instance.
+ *
+ */
+#ifndef libparc_parc_BufferComposer_h
+#define libparc_parc_BufferComposer_h
+
+struct parc_buffer_composer;
+typedef struct parc_buffer_composer PARCBufferComposer;
+
+#include <parc/algol/parc_Buffer.h>
+
+extern parcObjectDescriptor_Declaration(PARCBufferComposer);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcBufferComposer_OptionalAssertValid(_instance_)
+#else
+# define parcBufferComposer_OptionalAssertValid(_instance_) parcBufferComposer_AssertValid(_instance_)
+#endif
+
+/**
+ * Create an empty (zero-length) `PARCBufferComposer`.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to the new `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Create();
+ *
+ * // insert contents...
+ *
+ * parcBufferComposer_Release(&composer);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_Create(void);
+
+/**
+ * Create a new instance of `PARCBufferComposer` starting with an initial amount of dynamically allocated memory.
+ *
+ * The new buffer's position will be zero, its limit will be set to `length`, its capacity will be set to limit,
+ * its mark will be undefined, and each of its elements will be initialized to zero.
+ *
+ * @param [in] length The number of bytes to pre-allocate.
+ *
+ * @return A pointer to a `PARCBufferComposer` instance
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *buffer = parcBufferComposer_Allocate(10);
+ *
+ * parcBufferComposer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_Allocate(size_t length);
+
+/**
+ * Assert that an instance of `PARCBufferComposer` 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] instance A pointer to a PARCBufferComposer instance.
+ */
+void parcBufferComposer_AssertValid(const PARCBufferComposer *instance);
+
+/**
+ * This function returns a pointer to a shared `PARCBufferComposer`.
+ * An implementation may choose to produce a whole copy of the original `PARCBufferComposer`,
+ * or a reference counted pointer to a common copy.
+ *
+ * {@link parcBufferComposer_Release()} must perform the right operations to take care of a shared `PARCBufferComposer`,
+ * or simple copies.
+ *
+ * @param [in] original A pointer to a `PARCBufferComposer` that will be copied.
+ *
+ * @return A pointer to a `PARCBufferComposer`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *buffer = parcBufferComposer_Allocate(10);
+ *
+ * PARCBufferComposer *handle = parcBufferComposer_Acquire(buffer);
+ * // handle and buffer will be equal
+ *
+ * parcBufferComposer_Release(&handle);
+ * parcBufferComposer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_Acquire(const PARCBufferComposer *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] composerPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Create();
+ *
+ * parcBufferComposer_Release(&composer);
+ * }
+ * @endcode
+ */
+void parcBufferComposer_Release(PARCBufferComposer **composerPtr);
+
+/**
+ * Determine if two `PARCBufferComposer` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCBufferComposer` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcBufferComposer_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcBufferComposer_Equals(x, y)` must return true if and only if
+ * `parcBufferComposer_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcBufferComposer_Equals(x, y)` returns true and
+ * `parcBufferComposer_Equals(y, z)` returns true,
+ * then `parcBufferComposer_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcBufferComposer_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcBufferComposer_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] x A pointer to a `PARCBufferComposer` instance.
+ * @param [in] y A pointer to a `PARCBufferComposer` instance.
+ *
+ * @return true `PARCBufferComposer` x and y are equal.
+ * @return false `PARCBufferComposer` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composerA = parcBuffer_Allocate(10);
+ * PARCBufferComposer *composerB = parcBuffer_Allocate(10);
+ *
+ * if (parcBufferComposer_Equals(composerA, composerB)) {
+ * printf("Composers are equal.\n");
+ * } else {
+ * printf("Composers are NOT equal.\n");
+ * }
+ *
+ * parcBufferComposer_Release(&composerA);
+ * parcBufferComposer_Release(&composerB);
+ * }
+ * @endcode
+ */
+bool parcBufferComposer_Equals(const PARCBufferComposer *x, const PARCBufferComposer *y);
+
+/**
+ * Append `length` number of bytes from the given byte array `bytes` to the given `PARCBufferComposer`.
+ *
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * @param [in,out] composer A pointer to the PARCBufferComposer to receive the data.
+ * @param [in] bytes A pointer to the array that contains the data.
+ * @param [in] length The number of bytes of data to put into @p buffer.
+ *
+ * @return NULL Memory could not be allocated, and the buffer is unmodified.
+ * @return non-NULL The value of the parameter @p buffer.
+ *
+ * Example:
+ * @code
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(10);
+ * uint8_t string[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
+ *
+ * parcBufferComposer_PutArray(composer, string, strlen(string));
+ *
+ * parcBufferComposer_Release(&composer);
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_PutArray(PARCBufferComposer *composer, const unsigned char *bytes, size_t length);
+
+/**
+ * Append a single char to the given `PARCBufferComposer` at the current position.
+ *
+ * The buffer's position will be advanced by 1 (== sizeof(char)).
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance that will receive the char value.
+ * @param [in] value A single char value.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL The value of the parameter @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(10);
+ * parcBufferComposer_PutChar(composer, 0x12);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_PutChar(PARCBufferComposer *composer, char value);
+
+/**
+ * Append a single uint8_t to the given `PARCBufferComposer` at the current position.
+ *
+ * The buffer's position will be advanced by 1 (== sizeof(uint8_t)).
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance that will receive the uint8_t value.
+ * @param [in] value A uint8_t value.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL The value of the parameter @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(10);
+ * parcBufferComposer_PutUint8(composer, 0x12);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_PutUint8(PARCBufferComposer *composer, uint8_t value);
+
+/**
+ * Append a single uint16_t to the given `PARCBufferComposer` at the current position.
+ *
+ * The buffer's position will be advanced by 2.
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance that will receive the uint16_t value.
+ * @param [in] value A uint16_t value.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL The value of the parameter @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(10);
+ * parcBufferComposer_PutUint16(composer, 0x1234);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_PutUint16(PARCBufferComposer *composer, uint16_t value);
+
+/**
+ * Append a single uint16_t to the given `PARCBufferComposer` at the current position.
+ *
+ * The buffer's position will be advanced by 4.
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance that will receive the uint32_t value.
+ * @param [in] value A `uint32_t` value.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL The value of the parameter @p composer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(10);
+ * parcBufferComposer_PutUint32(composer, 0x12345678);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_PutUint32(PARCBufferComposer *composer, uint32_t value);
+
+/**
+ * Append a single uint64_t to the given `PARCBufferComposer` at the current position.
+ *
+ * The value is encoded in full, 8 byte, form in big-endian format, or network byte order.
+ * The buffer's position will be advanced by 8.
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance that will receive the uint64_t value.
+ * @param [in] value A `uint64_t` value.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL The value of the parameter @p composer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(20);
+ * parcBufferComposer_PutUint32(composer, 0x0123456789ABCDEF);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_PutUint64(PARCBufferComposer *composer, uint64_t value);
+
+/**
+ * Put (append) the content of the source buffer into the destination buffer.
+ *
+ * The contents are taken from the current position of the source buffer
+ * to its limit. The destination buffer is expanded as necessary.
+ *
+ * When complete, the source buffer's position is set to its limit.
+ *
+ * Both the input `PARCBufferComposer` and `PARCBuffer` instances are modified.
+ *
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance.
+ * @param [in] sourceBuffer The buffer that will produce the data.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL The value of the parameter @p composer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(1024);
+ * PARCBuffer *buffer = parcBuffer_AllocateCString("Hello, World!");
+ * parcBufferComposer_PutBuffer(composer, buffer);
+ * }
+ * @endcode
+ *
+ * @see parcBufferComposer_GetBuffer
+ */
+PARCBufferComposer *parcBufferComposer_PutBuffer(PARCBufferComposer *composer, const PARCBuffer *sourceBuffer);
+
+/**
+ * Put (append) the content of the null-terminated, C-style string into the destination buffer.
+ *
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance.
+ * @param [in] cString A pointer to a null-terminated C string to append to this `PARCBufferComposer`.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL The value of the parameter @p composer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(1024);
+ * parcBufferComposer_PutString(composer, "Hello, World!");
+ * // Hello, World!
+ * }
+ * @endcode
+ *
+ * @see parcBufferComposer_PutBuffer
+ * @see parcBufferComposer_GetBuffer
+ */
+PARCBufferComposer *parcBufferComposer_PutString(PARCBufferComposer *composer, const char *cString);
+
+/**
+ * Put (append) the content of an arbitrary number of null-terminated, C-style strings
+ * into the destination buffer.
+ *
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * @param [in,out] composer A pointer to a `PARCBufferComposer` instance.
+ * @param [in] ... The null-terminated, C-style strings to append to the given `PARCBufferComposer`.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL The value of the parameter @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(1024);
+ * parcBufferComposer_PutString(composer, "Hello");
+ * parcBufferComposer_PutStrings(composer, ", ", "World", "!");
+ * // Hello, World!
+ * }
+ * @endcode
+ *
+ * @see parcBufferComposer_PutString
+ * @see parcBufferComposer_PutBuffer
+ * @see parcBufferComposer_GetBuffer
+ */
+PARCBufferComposer *parcBufferComposer_PutStrings(PARCBufferComposer *composer, ...);
+
+/**
+ * Append a formatted nul-terminated, C string string to the given `PARCBufferComposer` instance.
+ * The input `PARCBufferComposer` instance is modified.
+ *
+ * The format string is a nul-terminated C string compatible with the `vasprintf(3)` C library function.
+ *
+ * @param [in,out] composer A pointer to `PARCBufferComposer`.
+ * @param [in] format The format string compatible with the `vasprintf(3)` C library function.
+ * @param [in] ... Remaining parameters used to format the string.
+ *
+ * @return The same pointer as the `composer` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(1024);
+ *
+ * parcBufferComposer_Format(composer, "Hello %s\n", "World");
+ *
+ * char *string = parcBuffer_ToString(parcBufferComposer_ProduceBuffer(string)));
+ * printf("String = %s\n", string);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcBufferComposer_Format(PARCBufferComposer *composer, const char *format, ...)
+__attribute__((format(printf, 2, 3)));
+
+/**
+ * Return a pointer to the underlying {@link PARCBuffer} instance currently used by the given `PARCBufferComposer`.
+ *
+ * WARNING: This function is not safe. Use with caution.
+ *
+ * There is no guarantee that the returned `PARCBuffer` instance will not
+ * be released and deallocated before use by the caller of this function.
+ * If modifications need to be made, a reference should be acquired manually.
+ *
+ * Also, if the caller modifies the state of the returned `PARCBuffer` instance,
+ * e.g., via a {@link parcBuffer_GetUint8}() call, any future writes to this
+ * same `PARCBufferComposer` will not behave as expected unless the instance is
+ * returned to its original state.
+ *
+ * To safely access the underlying `PARCBuffer` instance, use
+ * the {@link parcBufferComposer_CreateBuffer}() function instead.
+ *
+ * No new reference is created. The caller must acquire a reference to the returned `PARCBuffer`
+ * if it needs retain it beyond the life of the given `PARCBufferComposer`.
+ *
+ * @param composer [in] A pointer to a `PARCBufferComposer` instance.
+ *
+ * @return A pointer to the internal `PARCBuffer` which is wrapped by this `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(1024);
+ * PARCBuffer *buffer = parcBuffer_AllocateCString("Hello, World!");
+ * parcBufferComposer_PutBuffer(composer, buffer);
+ *
+ * PARCBuffer *sameBuffer = parcBufferComposer_GetBuffer(composer);
+ * // buffer and sameBuffer are equal
+ * }
+ * @endcode
+ *
+ * @see parcBufferComposer_PutBuffer
+ * @see parcBufferComposer_ProduceBuffer
+ */
+PARCBuffer *parcBufferComposer_GetBuffer(const PARCBufferComposer *composer);
+
+/**
+ * Create a `PARCBuffer` pointing to the underlying `PARCBuffer` instance.
+ *
+ * This is functionally equivalent to {@link parcBufferComposer_GetBuffer} but
+ * is safe since it allocates a new `PARCBuffer` instance for the same buffer.
+ *
+ * The result must be freed by the caller via {@link parcBuffer_Release}.
+ *
+ * @param [in] composer A pointer to a `PARCBufferComposer` instance.
+ *
+ * @return A pointer to the `PARCBuffer` which is stored by this `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(1024);
+ * PARCBuffer *buffer = parcBuffer_AllocateCString("Hello, World!");
+ * parcBufferComposer_PutBuffer(composer, buffer);
+ *
+ * PARCBuffer *writeBuffer = parcBufferComposer_CreateBuffer(composer);
+ *
+ * // use writeBuffer as needed
+ *
+ * parcBuffer_Release(&writeBuffer);
+ * }
+ * @endcode
+ *
+ * @see parcBufferComposer_GetBuffer
+ * @see parcBufferComposer_ProduceBuffer
+ */
+PARCBuffer *parcBufferComposer_CreateBuffer(PARCBufferComposer *composer);
+
+/**
+ * Finalize this `PARCBufferComposer` and return the resulting {@link PARCBuffer}.
+ *
+ * Note that, unlike {@link parcBufferComposer_GetBuffer}, the return buffer is flipped
+ * via {@link parcBuffer_Flip}. This effectively finalizes this `PARCBufferComposer`.
+ * No more writes should be made to this instance.
+ *
+ * Also note that {@link parcBufferComposer_ToString} cannot be called after this function
+ * is invoked.
+ *
+ * The result must be freed by the caller via {@link parcBuffer_Release}.
+ *
+ * @param [in] composer A pointer to a `PARCBufferComposer` instance.
+ *
+ * @return A pointer to the final `PARCBuffer` which is stored by this `PARCBufferComposer`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *composer = parcBufferComposer_Allocate(1024);
+ * PARCBuffer *buffer = parcBuffer_AllocateCString("Hello, World!");
+ * parcBufferComposer_PutBuffer(composer, buffer);
+ *
+ * PARCBuffer *readBuffer = parcBufferComposer_ProduceBuffer(composer);
+ * parcBufferComposer_Release(&composer);
+ *
+ * // use readBuffer as needed
+ *
+ * parcBuffer_Release(&readBuffer);
+ * }
+ * @endcode
+ *
+ * @see parcBufferComposer_GetBuffer
+ */
+PARCBuffer *parcBufferComposer_ProduceBuffer(PARCBufferComposer *composer);
+
+/**
+ * Produce a null-terminated string containing the characters from 0 to the current
+ * position of the given `PARCBufferComposer`.
+ * The composer is not modified and may continue to be used.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCBufferComposer 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
+ * {
+ * PARCBufferComposer *a = parcBufferComposer_Create();
+ *
+ * char *string = parcBufferComposer_ToString(a);
+ *
+ * parcBufferComposer_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ */
+char *parcBufferComposer_ToString(PARCBufferComposer *composer);
+#endif // libparc_parc_BufferComposer_h
diff --git a/libparc/parc/algol/parc_BufferDictionary.c b/libparc/parc/algol/parc_BufferDictionary.c
new file mode 100755
index 00000000..56ed800a
--- /dev/null
+++ b/libparc/parc/algol/parc_BufferDictionary.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 dictionary is implemented with the parc_HashCodeTable backend. This implementation
+ * is inefficient for additions with duplicate keys, because the semantics of parc_HashCodeTable
+ * are not the same as parc_BufferDictionary in returning values for Put and Remove.
+ *
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_BufferDictionary.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_HashCodeTable.h>
+
+struct parc_buffer_dictionary {
+ PARCHashCodeTable *hashtable;
+};
+
+// Wrapper to go from void * to PARCBuffer *
+static bool
+_parcBufferEquals(const void *a, const void *b)
+{
+ return parcBuffer_Equals((const PARCBuffer *) a, (const PARCBuffer *) b);
+}
+
+// Wrapper to go from void * to PARCBuffer *
+static PARCHashCode
+_parcBufferHashCode(const void *a)
+{
+ return parcBuffer_HashCode((const PARCBuffer *) a);
+}
+
+// Wrapper to go from void ** to PARCBuffer **
+static void
+_parcBufferRelease(void **bufferVoidPtr)
+{
+ parcBuffer_Release((PARCBuffer **) bufferVoidPtr);
+}
+
+/*
+ * Initialise a parcBufferDictionary instance.
+ * @return The same pointer as `result`.
+ */
+static PARCBufferDictionary *
+_init(PARCBufferDictionary *result)
+{
+ result->hashtable = parcHashCodeTable_Create(_parcBufferEquals, _parcBufferHashCode, _parcBufferRelease, _parcBufferRelease);
+ return result;
+}
+
+/**
+ * Cleans up the internal memory of a PARCBufferDictionary
+ *
+ * @param [in] dictionaryPtr Double pointer to the dictionary to finalize
+ */
+static void
+_destroy(PARCBufferDictionary **dictionaryPtr)
+{
+ assertNotNull(dictionaryPtr, "Double pointer dictionaryPtr must be non-NULL");
+ assertNotNull(*dictionaryPtr, "Double pointer dictionaryPtr must dereference to non-NULL");
+
+ PARCBufferDictionary *dict = *dictionaryPtr;
+
+ parcHashCodeTable_Destroy(&dict->hashtable);
+}
+
+
+parcObject_ExtendPARCObject(PARCBufferDictionary, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCBufferDictionary *
+parcBufferDictionary_Create(void)
+{
+ PARCBufferDictionary *result = parcObject_CreateInstance(PARCBufferDictionary);
+ if (result != NULL) {
+ return _init(result);
+ }
+
+ return NULL;
+}
+
+parcObject_ImplementAcquire(parcBufferDictionary, PARCBufferDictionary);
+
+parcObject_ImplementRelease(parcBufferDictionary, PARCBufferDictionary);
+
+PARCBuffer *
+parcBufferDictionary_Put(PARCBufferDictionary *dictionary, PARCBuffer *key, PARCBuffer *value)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-NULL");
+ assertNotNull(key, "Parameter key must be non-NULL");
+ assertNotNull(value, "Parameter value must be non-NULL");
+
+ PARCBuffer *oldValue = NULL;
+
+ // We use reference counted copyies of the supplied parameters
+ PARCBuffer *key_copy = parcBuffer_Acquire(key);
+ PARCBuffer *value_copy = parcBuffer_Acquire(value);
+
+ if (!parcHashCodeTable_Add(dictionary->hashtable, key_copy, value_copy)) {
+ // parcHashCodeTable_Del will free the referece, to make a copy of it
+ PARCBuffer *original = (PARCBuffer *) parcHashCodeTable_Get(dictionary->hashtable, key_copy);
+ oldValue = parcBuffer_Acquire(original);
+ parcHashCodeTable_Del(dictionary->hashtable, key_copy);
+ parcHashCodeTable_Add(dictionary->hashtable, key_copy, value_copy);
+ }
+
+ return oldValue;
+}
+
+PARCBuffer *
+parcBufferDictionary_Get(PARCBufferDictionary *dictionary, PARCBuffer *key)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-NULL");
+ assertNotNull(key, "Parameter key must be non-NULL");
+
+ return parcHashCodeTable_Get(dictionary->hashtable, key);
+}
+
+PARCBuffer *
+parcBufferDictionary_Remove(PARCBufferDictionary *dictionary, PARCBuffer *key)
+{
+ assertNotNull(dictionary, "Parameter dictionary must be non-NULL");
+ assertNotNull(key, "Parameter key must be non-NULL");
+
+ // parcHashCodeTable_Del will free the referece, to make a copy of it
+ PARCBuffer *original = (PARCBuffer *) parcHashCodeTable_Get(dictionary->hashtable, key);
+ PARCBuffer *oldValue = parcBuffer_Acquire(original);
+ parcHashCodeTable_Del(dictionary->hashtable, key);
+ return oldValue;
+}
diff --git a/libparc/parc/algol/parc_BufferDictionary.h b/libparc/parc/algol/parc_BufferDictionary.h
new file mode 100755
index 00000000..60aa90cb
--- /dev/null
+++ b/libparc/parc/algol/parc_BufferDictionary.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 parc_BufferDictionary.h
+ * @ingroup datastructures
+ * @brief A key/value dictionary built around PARCBuffer as the Key and the Value.
+ *
+ * The key/value dictionary models the Java MAP interface. It is built around Put, Get, and Remove.
+ * The dictionary stores references to the Key and Value, so the caller may destroy its references
+ * if no longer needed.
+ *
+ */
+#ifndef libparc_parc_BufferDictionary_h
+#define libparc_parc_BufferDictionary_h
+
+typedef struct parc_buffer_dictionary PARCBufferDictionary;
+
+#include <parc/algol/parc_Buffer.h>
+
+
+/**
+ * Creates an empty dictionary. You must use {@link parcBufferDictionary_Release} to destroy it.
+ *
+ * @return A pointer to the new `PARCBufferDictionary`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferDictionary *parcBufferDictionary_Create(void);
+
+/**
+ * Increase the number of references to a `PARCBufferDictionary`.
+ *
+ * Note that a new `PARCBufferDictionary` is not created,
+ * only that the given `PARCBufferDictionary` reference count is incremented.
+ * Discard the reference by invoking {@link parcBufferDictionary_Release}.
+ *
+ * @param [in] dictionary is a pointer to a `PARCBufferDictionary` instance
+ * @return The pointer to the @p dictionary instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferDictionary *parcBufferDictionary_Acquire(const PARCBufferDictionary *dictionary);
+
+/**
+ * Release a `PARCBufferDictionary` reference.
+ *
+ * Only the last invocation where the reference count is decremented to zero,
+ * will actually destroy the `PARCBufferDictionary`.
+ *
+ * @param [in,out] dictionaryPtr is a pointer to the `PARCBufferDictionary` reference.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcBufferDictionary_Release(PARCBufferDictionary **dictionaryPtr);
+
+/**
+ * Add a key/value to the dictionary, returns previous value or NULL
+ *
+ * The Dictionary will store a reference (PARCBuffer::aquire) to the key and to the value.
+ * The Key and Value must be non-NULL. If a previous entry for the key is in the dictionary,
+ * the previous value is returned. THE CALLER MUST USE {@link parcBuffer_Release} on the returned
+ * value if it is non-NULL;
+ *
+ * @param [in,out] dictionary The dictionary to modify
+ * @param [in] key The dictionary key
+ * @param [in] value The value for the key
+ *
+ * @return NULL The inserted key is unique
+ * @return non-NULL Returns the previous value of the key, must use {@link parcBuffer_Release}
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *parcBufferDictionary_Put(PARCBufferDictionary *dictionary, PARCBuffer *key, PARCBuffer *value);
+
+/**
+ * Returns the value associated with the key, or NULL if does not exist
+ *
+ * The returned value is what's stored in the dictionary in a `PARCBuffer` instance. If the user wishes to keep the
+ * value beyond the current calling scope, she should use {@link parcBuffer_Acquire} on the
+ * returned value.
+ *
+ * @param [in] dictionary The dictionary to query
+ * @param [in] key The dictionary key
+ *
+ * @return NULL The key is not in the dictionary
+ * @return non-NULL Returns the current value of the key, DO NOT use {@link parcBuffer_Release}
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *parcBufferDictionary_Get(PARCBufferDictionary *dictionary, PARCBuffer *key);
+
+/**
+ * Removes a key from the dictionary, returning the current value or NULL. The caller MUST
+ * call {@link parcBuffer_Release} on the returned value.
+ *
+ * @param [in,out] dictionary The dictionary to modify
+ * @param [in] key The dictionary key
+ *
+ * @return NULL The inserted key is not in the dictionary
+ * @return non-NULL Returns the current value of the key, DO NOT use {@link parcBuffer_Release}
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t phone[] = "6505551212";
+ * PARCBufferDictionary *dict = parcBufferDictionary_Create();
+ *
+ * parcBuffer *key = parcBuffer_Wrap(phone, sizeof(phone), 0);
+ * parcBuffer_Release(parcBufferDictionary_Remove(dict, key));
+ *
+ * parcBuffer_Release(&key);
+ * parcBufferDictionary_Destroy(&dict);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBufferDictionary_Remove(PARCBufferDictionary *dictionary, PARCBuffer *key);
+#endif // libparc_parc_BufferDictionary_h
diff --git a/libparc/parc/algol/parc_ByteArray.c b/libparc/parc/algol/parc_ByteArray.c
new file mode 100644
index 00000000..762421bd
--- /dev/null
+++ b/libparc/parc/algol/parc_ByteArray.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <ctype.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_ByteArray.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+struct parc_byte_array {
+ uint8_t *array;
+ size_t length;
+ void (*freeFunction)(void **);
+};
+#define MAGIC 0x0ddba11c1a55e5
+
+static inline void
+_trapIfOutOfBounds(const PARCByteArray *array, const size_t index)
+{
+ trapOutOfBoundsIf(index >= array->length, "parcByteArray index %zd exceeds the length %zd", index, array->length);
+}
+
+static bool
+_parcByteArray_Destructor(PARCByteArray **byteArrayPtr)
+{
+ PARCByteArray *byteArray = *byteArrayPtr;
+
+ if (byteArray->freeFunction != NULL) {
+ if (byteArray->array != NULL) {
+ byteArray->freeFunction((void **) &(byteArray->array));
+ }
+ }
+ return true;
+}
+
+parcObject_Override(PARCByteArray, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcByteArray_Destructor,
+ .copy = (PARCObjectCopy *) parcByteArray_Copy,
+ .equals = (PARCObjectEquals *) parcByteArray_Equals,
+ .compare = (PARCObjectCompare *) parcByteArray_Compare,
+ .hashCode = (PARCObjectHashCode *) parcByteArray_HashCode,
+ .display = (PARCObjectDisplay *) parcByteArray_Display);
+
+void
+parcByteArray_AssertValid(const PARCByteArray *instance)
+{
+ trapInvalidValueIf(parcByteArray_IsValid(instance) == false,
+ "PARCByteArray instance is invalid.");
+}
+
+bool
+parcByteArray_IsValid(const PARCByteArray *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ if (instance->length == 0 || instance->array != NULL) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+PARCByteArray *
+parcByteArray_Allocate(const size_t length)
+{
+ uint8_t *array = NULL;
+ if (length > 0) {
+ array = parcMemory_AllocateAndClear(sizeof(uint8_t) * length);
+ if (array == NULL) {
+ return NULL;
+ }
+ }
+ PARCByteArray *result = parcObject_CreateInstance(PARCByteArray);
+
+ if (result != NULL) {
+ result->array = array;
+ result->length = length;
+ result->freeFunction = parcMemory_DeallocateImpl;
+ return result;
+ } else {
+ parcMemory_Deallocate(&array);
+ }
+ return NULL;
+}
+
+PARCByteArray *
+parcByteArray_Wrap(const size_t length, uint8_t array[length])
+{
+ if (array != NULL) {
+ PARCByteArray *result = parcObject_CreateInstance(PARCByteArray);
+ if (result != NULL) {
+ result->array = array;
+ result->length = length;
+ result->freeFunction = NULL;
+ return result;
+ }
+ }
+ return NULL;
+}
+
+parcObject_ImplementAcquire(parcByteArray, PARCByteArray);
+
+parcObject_ImplementRelease(parcByteArray, PARCByteArray);
+
+PARCByteArray *
+parcByteArray_Copy(const PARCByteArray *original)
+{
+ parcByteArray_OptionalAssertValid(original);
+
+ PARCByteArray *result = NULL;
+
+ if (original != NULL) {
+ result = parcByteArray_Allocate(original->length);
+ memcpy(result->array, original->array, result->length);
+ }
+
+ return result;
+}
+
+size_t
+parcByteArray_Capacity(const PARCByteArray *byteArray)
+{
+ parcByteArray_OptionalAssertValid(byteArray);
+ return byteArray->length;
+}
+
+PARCByteArray *
+parcByteArray_PutByte(PARCByteArray *result, size_t index, uint8_t byte)
+{
+ parcByteArray_OptionalAssertValid(result);
+ _trapIfOutOfBounds(result, index);
+
+ result->array[index] = byte;
+ return result;
+}
+
+uint8_t
+parcByteArray_GetByte(const PARCByteArray *array, size_t index)
+{
+ parcByteArray_OptionalAssertValid(array);
+ _trapIfOutOfBounds(array, index);
+
+ return array->array[index];
+}
+
+uint8_t *
+parcByteArray_Array(const PARCByteArray *byteArray)
+{
+ parcByteArray_OptionalAssertValid(byteArray);
+ return byteArray->array;
+}
+
+uint8_t *
+parcByteArray_AddressOfIndex(const PARCByteArray *array, const size_t index)
+{
+ parcByteArray_OptionalAssertValid(array);
+ _trapIfOutOfBounds(array, index);
+
+ return &array->array[index];
+}
+
+int
+parcByteArray_Compare(const PARCByteArray *x, const PARCByteArray *y)
+{
+ if (x == y) {
+ return 0;
+ }
+
+ if (x == NULL) {
+ return -1;
+ }
+
+ if (y == NULL) {
+ return +1;
+ }
+
+ if (parcByteArray_Capacity(x) > parcByteArray_Capacity(y)) {
+ return +1;
+ }
+ if (parcByteArray_Capacity(x) < parcByteArray_Capacity(y)) {
+ return -1;
+ }
+
+ return memcmp(x->array, y->array, parcByteArray_Capacity(x));
+}
+
+PARCByteArray *
+parcByteArray_PutBytes(PARCByteArray *result, size_t offset, size_t length, const uint8_t source[length])
+{
+ parcByteArray_OptionalAssertValid(result);
+ trapOutOfBoundsIf(offset > result->length,
+ "The offset (%zd) exeeds the length (%zd) of the PARCByteArray.", offset, result->length);
+
+ size_t available = result->length - offset;
+
+ trapOutOfBoundsIf(length > available, "%zd available bytes, %zd required.", available, length);
+
+ memcpy(&result->array[offset], source, length);
+ return result;
+}
+
+PARCByteArray *
+parcByteArray_GetBytes(const PARCByteArray *result, size_t offset, size_t length, uint8_t array[length])
+{
+ parcByteArray_OptionalAssertValid(result);
+
+ size_t available = result->length - offset;
+
+ trapOutOfBoundsIf(length > available, "parcByteArray_CopyOut %zd available bytes, %zd required", available, length);
+
+ memcpy(array, &result->array[offset], length);
+ return (PARCByteArray *) result;
+}
+
+PARCByteArray *
+parcByteArray_ArrayCopy(PARCByteArray *destination, size_t destOffset, const PARCByteArray *source, size_t srcOffset, size_t length)
+{
+ parcByteArray_OptionalAssertValid(destination);
+ parcByteArray_OptionalAssertValid(source);
+
+ memcpy(&destination->array[destOffset], &source->array[srcOffset], length);
+ return destination;
+}
+
+bool
+parcByteArray_Equals(const PARCByteArray *a, const PARCByteArray *b)
+{
+ if (a == b) {
+ return true;
+ }
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+ if (a->length == b->length) {
+ return memcmp(a->array, b->array, a->length) == 0;
+ }
+ return false;
+}
+
+static void
+_parcByteArray_PrettyPrintLine(const unsigned char *memory, size_t offset, size_t length)
+{
+ int bytesPerLine = 16;
+ char accumulator[bytesPerLine + 1];
+ memset(accumulator, ' ', bytesPerLine);
+ accumulator[bytesPerLine] = 0;
+
+ printf("%5zd: ", offset);
+
+ for (int i = 0; i < bytesPerLine; i++) {
+ if (offset + i >= length) {
+ printf(" ");
+ accumulator[i] = ' ';
+ } else {
+ char c = memory[offset + i];
+ printf("0x%02x, ", c & 0xFF);
+ if (isprint(c)) {
+ accumulator[i] = c;
+ } else {
+ accumulator[i] = '.';
+ }
+ }
+ }
+ printf(" %s\n", accumulator);
+}
+
+void
+parcByteArray_Display(const PARCByteArray *array, int indentation)
+{
+ int bytesPerLine = 16;
+
+ if (array->array == NULL) {
+ parcDisplayIndented_PrintLine(indentation, "PARCByteArray@NULL");
+ } else {
+ parcDisplayIndented_PrintLine(indentation, "PARCByteArray@%p = [0,%zd)", (void *) array, array->length);
+
+ for (size_t offset = 0; offset < array->length; offset += bytesPerLine) {
+ _parcByteArray_PrettyPrintLine(array->array, offset, array->length);
+ }
+ }
+}
+
+PARCHashCode
+parcByteArray_HashCode(const PARCByteArray *array)
+{
+ parcByteArray_OptionalAssertValid(array);
+ return parcHashCode_Hash(array->array, array->length);
+}
diff --git a/libparc/parc/algol/parc_ByteArray.h b/libparc/parc/algol/parc_ByteArray.h
new file mode 100644
index 00000000..98cc970a
--- /dev/null
+++ b/libparc/parc/algol/parc_ByteArray.h
@@ -0,0 +1,580 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_ByteArray.h
+ * @ingroup memory
+ * @brief A simple reference counted unsigned byte array.
+ *
+ * @htmlonly
+ * <svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" version="1.1" viewBox="48 74 304 68" width="304pt" height="68pt">
+ * <defs>
+ * <font-face font-family="Helvetica Neue" font-size="10" panose-1="2 0 5 3 0 0 0 2 0 4" units-per-em="1000" underline-position="-100" underline-thickness="50" slope="0" x-height="517" cap-height="714" ascent="951.99585" descent="-212.99744" font-weight="500">
+ * <font-face-src>
+ * <font-face-name name="HelveticaNeue"/>
+ * </font-face-src>
+ * </font-face>
+ * <marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="black">
+ * <g>
+ * <path d="M 8 0 L 0 -3 L 0 3 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/>
+ * </g>
+ * </marker>
+ * </defs>
+ * <g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
+ * <title>icon_512x512</title>
+ * <rect fill="white" width="512" height="512"/>
+ * <g>
+ * <title>Layer 1</title>
+ * <text transform="translate(271 88.5)" fill="black">
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x=".185" y="10" textLength="39.63">Capacity</tspan>
+ * </text>
+ * <text transform="translate(83 88.5)" fill="black">
+ * <tspan font-family="Helvetica Neue" font-size="10" font-weight="500" x=".245" y="10" textLength="23.51">Array</tspan>
+ * </text>
+ * <path d="M 78 96.483333 C 73.6671 96.98884 67.757544 94.49623 65 98 C 63.49089 99.917494 62.925312 103.63153 62.52875 107.66717" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <rect x="59" y="118" width="281" height="13" fill="white"/>
+ * <rect x="59" y="118" width="281" height="13" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * <path d="M 316 97.11628 C 321.9994 97.744123 330.42197 95.601626 334 99 C 335.8631 100.769544 336.41326 104.04195 336.67595 107.643264" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
+ * </g>
+ * </g>
+ * </svg>
+ * @endhtmlonly
+ *
+ * `PARCByteArray` is a simple reference counted array of `uint8_t` values.
+ * Instances of `PARCByteArray` are created either by dynamically allocating the byte array,
+ * via `parcByteArray_Allocate()`,
+ * or by wrapping a static `uint8_t` array,
+ * via `parcByteArray_Wrap()`.
+ *
+ * New references to an existing instance of `PARCByteArray` are created via `parcByteArray_Acquire()`.
+ *
+ * A `PARCByteArray` reference is released via `parcByteArray_Release`.
+ * Only the last invocation will deallocated the `PARCByteArray`.
+ * If the `PARCByteArray` references dynamically allocated memory,
+ * that memory is freed with the `PARCByteArray` when the last reference is released.
+ *
+ */
+#ifndef libparc_parc_ByteArray_h
+#define libparc_parc_ByteArray_h
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+struct parc_byte_array;
+/**
+ *
+ * @see {@link parcByteArray_Allocate}
+ * @see {@link parcByteArray_Wrap}
+ */
+typedef struct parc_byte_array PARCByteArray;
+
+#include <parc/algol/parc_HashCode.h>
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcByteArray_OptionalAssertValid(_instance_)
+#else
+# define parcByteArray_OptionalAssertValid(_instance_) parcByteArray_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that an instance of `PARCByteArray` 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] instance A pointer to a `PARCByteArray` instance.
+ */
+void parcByteArray_AssertValid(const PARCByteArray *instance);
+
+/**
+ * Determine if an instance of `PARCByteArray` 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 `PARCByteArray` instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ */
+bool parcByteArray_IsValid(const PARCByteArray *instance);
+
+/**
+ * Dynamically allocate a `PARCByteArray` of a specific capacity.
+ *
+ * @param [in] capacity The number of bytes in the byte array.
+ *
+ * @return A pointer to an allocated `PARCByteArray` instance which must be released via {@link parcByteArray_Release()}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCByteArray *byteArray = parcByteArray_Allocate(100);
+ *
+ * parcByteArray_Release(&byteArray);
+ * }
+ * @endcode
+ *
+ * @see parcByteArray_Release
+ */
+PARCByteArray *parcByteArray_Allocate(const size_t capacity);
+
+/**
+ * Wrap existing memory in a {@link PARCByteArray}.
+ *
+ * As in all `Wrap` functions, a copy of the memory is not made.
+ * Be sure to only wrap memory that is either global,
+ * or used within on stack-frame or functional block.
+ * Otherwise, corruption is likly to occur.
+ *
+ * @param [in] capacity The maximum capacity of the backing array.
+ * @param [in] array A pointer to the backing array.
+ *
+ * @return A pointer to an allocated `PARCByteArray` instance which must be released via {@link parcByteArray_Release()}.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray = parcByteArray_Wrap(array, 10);
+ *
+ * parcByteArray_Release(&byteArray);
+ * }
+ * @endcode
+ */
+PARCByteArray *parcByteArray_Wrap(size_t capacity, uint8_t *array);
+
+/**
+ * Returns the pointer to the `uint8_t` array that backs this `PARCByteArray`.
+ *
+ * Modifications to the given `PARCByteArray` content will cause the returned array's content to be modified, and vice versa.
+ *
+ * The reference count for the given `PARCByteArray` is not modified.
+ *
+ * <b>Use with caution.</b>
+ *
+ * @param [in] byteArray Pointer to a `PARCByteArray` instance from which the underlying array is extracted.
+ *
+ * @return The pointer to the `uint8_t` array that backs this `PARCByteArray`.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray = parcByteArray_Wrap(array, 10);
+ *
+ * uint8_t *raw = parcByteArray_Array(byteArray);
+ * // updates on the raw array (pointer) are seen in the byteArray instance
+ * // use with caution
+ *
+ * parcByteArray_Release(&byteArray);
+ * }
+ * @endcode
+ */
+uint8_t *parcByteArray_Array(const PARCByteArray *byteArray);
+
+/**
+ * Increase the number of references to a `PARCByteArray`.
+ *
+ * Note that a new `PARCByteArray` is not created,
+ * only that the given `PARCByteArray` reference count is incremented.
+ * Discard the reference by invoking {@link parcByteArray_Release}.
+ *
+ * @param [in] instance A pointer to the original `PARCByteArray` instance.
+ *
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCByteArray *x = parcByteArray_Allocate(10);
+ *
+ * PARCByteArray *x_2 = parcByteArray_Acquire(x);
+ *
+ * parcByteArray_Release(&x);
+ * parcByteArray_Release(&x_2);
+ * }
+ * @endcode
+ *
+ * @see parcByteArray_Release
+ */
+PARCByteArray *parcByteArray_Acquire(const PARCByteArray *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] byteArrayPtr A pointer to a pointer to the instance of `PARCByteArray` to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCByteArray *x = parcByteArray_Acquire(...);
+ *
+ * parcByteArray_Release(&x);
+ * }
+ * @endcode
+ */
+void parcByteArray_Release(PARCByteArray **byteArrayPtr);
+
+/**
+ * Put an `uint8_t` value into the byte array at the given index.
+ *
+ * The value of @p index must be greater than or equal to 0, and less than the capacity.
+ *
+ * @param [in,out] result A pointer to the instance of `PARCByteArray` that will receive the data.
+ * @param [in] index The index at which the byte will be inserted.
+ * @param [in] byte The byte to be inserted into the array.
+ *
+ * @return The `PARCByteArray` that receive the data.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray = parcByteArray_Wrap(array, 10);
+ *
+ * parcByteArray_PutByte(byteArray, 5, 123);
+ *
+ * parcByteArray_Release(&byteArray);
+ * }
+ * @endcode
+ */
+PARCByteArray *parcByteArray_PutByte(PARCByteArray *result, size_t index, uint8_t byte);
+
+/**
+ * Get the value at a specific index from the given `PARCByteArray`.
+ *
+ * @param [in] result The instance of `PARCByteArray` that will produce the data.
+ * @param [in] index The index from which the byte will be retrieved.
+ *
+ * @return The value at a specific index from the given `PARCByteArray`.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray = parcByteArray_Wrap(array, 10);
+ *
+ * parcByteArray_PutByte(byteArray, 5, 123);
+ *
+ * parcByteArray_GetByte(byteArray, 5);
+ *
+ * parcByteArray_Release(&byteArray);
+ * }
+ * @endcode
+ */
+uint8_t parcByteArray_GetByte(const PARCByteArray *result, size_t index);
+
+/**
+ * Compares instance a with instance b for order.
+ *
+ * Returns a negative integer, zero, or a positive integer as instance a is less than, equal to, or greater than instance b.
+ *
+ * @param [in] a A pointer to a `PARCByteArray` instance 'a'.
+ * @param [in] b A pointer to another `PARCByteArray` instance 'b'.
+ *
+ * @return <0 Instance a is less then instance b.
+ * @return 0 Instance a and instance b compare the same.
+ * @return >0 Instance a is greater than instance b.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray1 = parcByteArray_Wrap(array, 10);
+ * PARCByteArray *byteArray2 = parcByteArray_Wrap(array, 10);
+ *
+ * if (parcByteArray_Compare(byteArray1, byteArray2) == 0) {
+ * printf("Equal\n");
+ * }
+ *
+ * parcByteArray_Release(&byteArray1);
+ * parcByteArray_Release(&byteArray2);
+ * }
+ * @endcode
+ *
+ * @see parcByteArray_Equal
+ */
+int parcByteArray_Compare(const PARCByteArray *a, const PARCByteArray *b);
+
+/**
+ * Copy data from an external array into a `PARCByteArray`.
+ *
+ * Provided that the underlying `PARCByteArray` is large enough,
+ * copy the bytes from the given `array` for `length` bytes.
+ *
+ * @param [in,out] result The `PARCByteArray` that will receive the data.
+ * @param [in] offset The offset into the `PARCByteArray` that will receive the data.
+ * @param [in] length The number of bytes to copy in.
+ * @param [in] source The uint8_t array containing the original data.
+ *
+ * @return The given `PARCByteArray` pointer
+ *
+ * @throws SIGABRT `trapOutOfBounds` if the underlying `PARCByteArray` is not large enough
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray = parcByteArray_Wrap(array, 10);
+ * uint8_t inner[3];
+ * inner[0] = 0xFF;
+ * inner[1] = 0xFF;
+ * inner[2] = 0xFF;
+ *
+ * parcByteArray_PutBytes(byteArray, 1, 3, inner);
+ * // Bytes 1,2,3 of byteArray will be 0xFF (offset was 1, not 0)
+ *
+ * parcByteArray_Release(&byteArray);
+ * }
+ * @endcode
+ */
+PARCByteArray *parcByteArray_PutBytes(PARCByteArray *result, size_t offset, size_t length, const uint8_t *source);
+
+/**
+ * Copy data from a `PARCByteArray` into an external array.
+ *
+ * Provided that the underlying `PARCByteArray` has at least `length` bytes
+ * copy the bytes from the `PARCByteArray` into the given `array`.
+ *
+ * @param [in] source The `PARCByteArray` that will produce the data.
+ * @param [in] offset The offset into the `PARCByteArray` from which the data will be copied.
+ * @param [in] length The number of bytes to copy from the <code>PARCByteArray</code> into @p destination.
+ * @param [in] destination The `uint8_t` array That will contain the data.
+ *
+ * @return The given `PARCByteArray` @p source pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray = parcByteArray_Wrap(array, 10);
+ *
+ * uint8_t inner[3];
+ * parcByteArray_GetBytes(byteArray, 0, 3, inner);
+ * // inner will contain a copy of bytes 0,1,2 from the byteArray
+ *
+ * parcByteArray_Release(&byteArray);
+ * }
+ * @endcode
+ */
+PARCByteArray *parcByteArray_GetBytes(const PARCByteArray *source, size_t offset, size_t length, uint8_t *destination);
+
+
+/**
+ * Copy a portion of one `PARCByteArray` into another.
+ *
+ * The sum of (destination/source) offset and length must be within the bounds of the
+ * respective (destination/source) `PARCByteArray` instances.
+ *
+ * @param [in,out] destination Pointer to the destination `PARCByteArray` instance.
+ * @param [in] destOffset Offset within the destination `PARCByteArray` instance.
+ * @param [in] source Pointer to the source `PARCByteArray` instance.
+ * @param [in] srcOffset Offset within the source `PARCByteArray` instance.
+ * @param [in] length Number of bytes to copy from the source to the destination.
+ *
+ * @return PARCByteArray* A pointer to the destination.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array1[10];
+ * PARCByteArray *byteArray1 = parcByteArray_Wrap(array1, 10);
+ * uint8_t array2[3];
+ * array2[0] = 0xAA;
+ * array2[1] = 0xBB;
+ * array2[2] = 0xCC;
+ * PARCByteArray *byteArray2 = parcByteArray_Wrap(array2, 3);
+ *
+ * parcByteArray_ArrayCopy(byteArray1, 0, byteArray2, 0, 3);
+ * // the first three bytes of byteArray1 will now be 0xAA,0xBB,0xCC
+ * }
+ * @endcode
+ */
+PARCByteArray *parcByteArray_ArrayCopy(PARCByteArray *destination, size_t destOffset, const PARCByteArray *source, size_t srcOffset, size_t length);
+
+/**
+ * Get the capacity of a `PARCByteArray`.
+ *
+ * The `PARCByteArray`'s capacity is the number of bytes stored in the backing store of a `PARCByteArray`.
+ *
+ * @param [in] byteArray Pointer to the `PARCByteArray` instance being examined.
+ *
+ * @return The capacity of a `PARCByteArray`.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray = parcByteArray_Wrap(array, 10);
+ *
+ * size_t capacity = parcByteArray_Capacity(byteArray);
+ * }
+ * @endcode
+ */
+size_t parcByteArray_Capacity(const PARCByteArray *byteArray);
+
+/**
+ * Create a copy of an existing `PARCByteArray`.
+ *
+ * The copy is equal to, but shares nothing in common with, the original `PARCByteArray`
+ *
+ * @param [in] original A non-null pointer to the `PARCByteArray` to copy.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to the new `PARCByteArray` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray = parcByteArray_Wrap(array, 10);
+ * PARCByteArray *copy = parcByteArray_Copy(byteArray);
+ * }
+ * @endcode
+ *
+ * @see parcByteArray_Allocate
+ * @see parcByteArray_Wrap
+ */
+PARCByteArray *parcByteArray_Copy(const PARCByteArray *original);
+
+/**
+ * Determine if two `PARCByteArray` instances are equal.
+ *
+ * Two `PARCByteArray` instances are equal if, and only if,
+ * * They have the same number of elements, and
+ * * The two sequences of remaining elements are pointwise equal.
+ *
+ * The following equivalence relations on non-null `PARCByteArray` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcByteArray_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcByteArray_Equals(x, y)` must return true if and only if
+ * `parcByteArray_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcByteArray_Equals(x, y)` returns true and
+ * `parcByteArray_Equals(y, z)` returns true,
+ * then `parcByteArray_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcByteArray_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcByteArray_Equals(x, NULL)` must return false.
+ *
+ * @param [in] a A pointer to a `PARCByteArray` instance.
+ * @param [in] b A pointer to a `PARCByteArray` instance.
+ *
+ * @return true if the two `PARCByteArray` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10];
+ * PARCByteArray *byteArray1 = parcByteArray_Wrap(array, 10);
+ * PARCByteArray *byteArray2 = parcByteArray_Wrap(array, 10);
+ *
+ * if (parcByteArray_Equals(byteArray1, byteArray2)) {
+ * printf("Equal\n");
+ * } else {
+ * printf("NOT Equal\n");
+ * }
+ *
+ * parcByteArray_Release(&byteArray1);
+ * parcByteArray_Release(&byteArray2);
+ * }
+ * @endcode
+ */
+bool parcByteArray_Equals(const PARCByteArray *a, const PARCByteArray *b);
+
+/**
+ * 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 {@link parcByteArray_HashCode} function must consistently return the same value,
+ * provided no information used in a corresponding {@link parcByteArray_Equals}
+ * 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 parcByteArray_Equals} method,
+ * then calling the {@link parcByteArray_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 parcByteArray_Equals} function,
+ * then calling the {@link parcByteArray_HashCode}
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] array A pointer to the `PARCByteArray` instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCByteArray *array = parcByteArray_Allocate(10);
+ * uint32_t hashValue = parcByteArray_HashCode(array);
+ * parcByteArray_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcByteArray_HashCode
+ */
+PARCHashCode parcByteArray_HashCode(const PARCByteArray *array);
+
+/**
+ * Return the memory address as a `uint8_t *` to the location specified by `index`.
+ *
+ * @param [in] array A pointer to the `PARCByteArray` instance.
+ * @param [in] index The index of the address.
+ *
+ * @return A pointer to the location offset by index bytes within the array.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCByteArray *byteArray = parcByteArray_Allocate(10);
+ * uint8_t *offsetAddress = parcByteArray_AddressOfIndex(byteArray, 4);
+ * // offsetAddress now points to the array at offset 4 within byteArray
+ * }
+ * @endcode
+ */
+uint8_t *parcByteArray_AddressOfIndex(const PARCByteArray *array, size_t index);
+
+/**
+ * Pretty print the given `PARCByteArray` instance.
+ *
+ * @param [in] indentation The amount of indentation to prefix each line of output
+ * @param [in] array The `PARCByteArray` instance to be printed.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCByteArray *byteArray = parcByteArray_Allocate(10);
+ * parcByteArray_Display(byteArray, 0);
+ * }
+ * @endcode
+ */
+void parcByteArray_Display(const PARCByteArray *array, int indentation);
+#endif // libparc_parc_ByteArray_h
diff --git a/libparc/parc/algol/parc_CMacro.h b/libparc/parc/algol/parc_CMacro.h
new file mode 100644
index 00000000..a47129ea
--- /dev/null
+++ b/libparc/parc/algol/parc_CMacro.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.
+ */
+
+/**
+ * @file parc_CMacro.h
+ * @ingroup Macro
+ * @brief Utility C-Macros
+ *
+ * CMacro contains a set of utility macros for doing complicated macro processing
+ *
+ */
+#ifndef libparc_parc_CMacro_h
+#define libparc_parc_CMacro_h
+
+/**
+ * parcCMacro_ThridParam expands to the "3rd" input parameter whatever that may be. It is a part
+ * of the c-macro trick for implement a macro If-Else switch. If the first argument expands
+ * to a comma then this macro expands to the second parameter, otherwise it expands to the 3rd parameter.
+ */
+#define parcCMacro_ThirdParam(A, B, C, ...) C
+
+/**
+ * parcCMacro_IfElse is a c-macro trick for implementing a macro If-Else switch.
+ * It uses parcCMacro_ThirdParam to select between A or B depending on whether __VA_ARGS__ expands to a comma.
+ */
+#define parcCMacro_IfElse(A, B, ...) parcCMacro_ThirdParam(__VA_ARGS__, A, B, NOOP)
+
+/** \cond */
+#define _parcCMacro_Cat_(A, B) A ## B
+/** \endcond */
+
+/**
+ * parcCMacro_Cat combines two strings into a single token.
+ */
+#define parcCMacro_Cat(A, B) _parcCMacro_Cat_(A, B)
+
+#endif //libparc_parc_CMacro_h
diff --git a/libparc/parc/algol/parc_Chunker.c b/libparc/parc/algol/parc_Chunker.c
new file mode 100755
index 00000000..b84ed05f
--- /dev/null
+++ b/libparc/parc/algol/parc_Chunker.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 <string.h>
+#include <sys/time.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_Chunker.h>
+
+struct parc_chunker {
+ PARCObject *instance;
+ const PARCChunkerInterface *interface;
+};
+
+static void
+_destroy(PARCChunker **chunkerP)
+{
+ parcObject_Release(&(*chunkerP)->instance);
+}
+
+
+parcObject_ExtendPARCObject(PARCChunker, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+parcObject_ImplementAcquire(parcChunker, PARCChunker);
+parcObject_ImplementRelease(parcChunker, PARCChunker);
+
+PARCChunker *
+parcChunker_Create(PARCObject *instance, PARCChunkerInterface *interface)
+{
+ PARCChunker *chunker = parcObject_CreateInstance(PARCChunker);
+
+ if (chunker != NULL) {
+ chunker->instance = parcObject_Acquire(instance);
+ chunker->interface = interface;
+ }
+
+ return chunker;
+}
+
+PARCIterator *
+parcChunker_ForwardIterator(const PARCChunker *chunker)
+{
+ return (chunker->interface)->ForwardIterator(chunker->instance);
+}
+
+PARCIterator *
+parcChunker_ReverseIterator(const PARCChunker *chunker)
+{
+ return (chunker->interface)->ReverseIterator(chunker->instance);
+}
+
+size_t
+parcChunker_GetChunkSize(const PARCChunker *chunker)
+{
+ return (chunker->interface)->GetChunkSize(chunker->instance);
+}
diff --git a/libparc/parc/algol/parc_Chunker.h b/libparc/parc/algol/parc_Chunker.h
new file mode 100755
index 00000000..305acad7
--- /dev/null
+++ b/libparc/parc/algol/parc_Chunker.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 parc_Chunker.h
+ * @ingroup ContentObject
+ * @brief A Chunker is an object that breaks up a large piece of data from a `PARCBuffer`
+ * or a file and provides an iterator to walk over the chunks in sequential order.
+ *
+ */
+
+#ifndef libparc_parc_Chunker_h
+#define libparc_parc_Chunker_h
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Iterator.h>
+
+struct parc_chunker;
+/**
+ * @typedef PARCChunker
+ * @brief The PARC Chunker
+ */
+typedef struct parc_chunker PARCChunker;
+
+typedef struct PARCChunkerInterface {
+ /**
+ * @see parcChunker_ForwardIterator
+ */
+ void *(*ForwardIterator)(const void *original);
+
+ /**
+ * @see parcChunker_ReverseIterator
+ */
+ void *(*ReverseIterator)(const void *original);
+
+ /**
+ * @see parcChunker_GetChunkSize
+ */
+ size_t (*GetChunkSize)(const void *original);
+} PARCChunkerInterface;
+
+/**
+ * Create a new chunker from the given concrete instance.
+ *
+ * @param [in] instance A `PARCChunker` instance.
+ * @param [in] interface The interface implementation of the chunker.
+ *
+ * @retval PARCChunker A newly allocated `PARCChunker`
+ * @retval NULL An error occurred.
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCChunkerBuffer *bufferChunker = parcBufferChunker_Create(dataToChunk, 32);
+ * PARCChunker *chunker = parcChunker_Create(bufferCunker, &PARCBufferChunkerAsChunker);
+ * }
+ */
+PARCChunker *parcChunker_Create(PARCObject *instance, PARCChunkerInterface *interface);
+
+/**
+ * Create a new chunker to segment data contained in a file.
+ *
+ * @param [in] fileName The name of a file from which to read.
+ * @param [in] chunkSize The size per chunk.
+ *
+ * @retval PARCChunker A newly allocated `PARCChunker`
+ * @retval NULL An error occurred.
+ *
+ * Example
+ * @code
+ * {
+ * char *bigFileName = "big_file.bin";
+ * PARCChunker *chunker = parcChunker_CreateFromBuffer(bigFileName, 32);
+ * }
+ */
+//PARCChunker *parcChunker_CreateFromFile(char *fileName, size_t maxDataSize);
+
+/**
+ * Increase the number of references to a `PARCChunker` instance.
+ *
+ * Note that new `PARCChunker` is not created,
+ * only that the given `PARCChunker` reference count is incremented.
+ * Discard the reference by invoking {@link parcChunker_Release}.
+ *
+ * @param [in] chunker A pointer to the original `PARCChunker`.
+ * @return The value of the input parameter @p chunker.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCChunker *original = ...
+ *
+ * PARCChunker *reference = parcChunker_Acquire(original);
+ *
+ * parcChunker_Release(&original);
+ * parcChunker_Release(&reference);
+ * }
+ * @endcode
+ *
+ * @see parcChunker_Release
+ */
+PARCChunker *parcChunker_Acquire(const PARCChunker *chunker);
+
+/**
+ * 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] chunkerP A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCChunker *chunker = parcChunker_Acquire(instance);
+ *
+ * parcChunker_Release(&chunker);
+ * }
+ * @endcode
+ */
+void parcChunker_Release(PARCChunker **chunkerP);
+
+/**
+ * Determine if two `PARCChunker` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCChunker` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcChunker_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcChunker_Equals(x, y)` must return true if and only if
+ * `parcChunker_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcChunker_Equals(x, y)` returns true and
+ * `parcChunker_Equals(y, z)` returns true,
+ * then `parcChunker_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcChunker_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcChunker_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param chunkerA A pointer to a `PARCChunker` instance.
+ * @param chunkerB A pointer to a `PARCChunker` instance.
+ * @return true if the two `PARCChunker` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCChunker *chunkerA = ...
+ * PARCChunker *chunkerB = ...
+ *
+ * bool equals = parcChunker_Equals(chunkerA, chunkerB);
+ * }
+ * @endcode
+ */
+bool parcChunker_Equals(const PARCChunker *chunkerA, const PARCChunker *chunkerB);
+
+/**
+ * Return an iterator to traverse the chunks of the underlying data in sequential order.
+ *
+ * This function can only be called once per chunker instance since the iterator
+ * will mutate internal state of the chunker.
+ *
+ * @param [in] chunker A `PARCChunker` instance.
+ *
+ * @return a `PARCIterator` that traverses the chunks of the underlying data.
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCBufferChunker *chunker = ...
+ *
+ * PARCIterator *itr = parcChunker_ForwardIterator(chunker);
+ *
+ * // use the iterator to traverse the chunker
+ * }
+ * @endcode
+ */
+PARCIterator *parcChunker_ForwardIterator(const PARCChunker *chunker);
+
+/**
+ * Return an iterator to traverse the chunks of the underlying data in sequential order.
+ *
+ * This function can only be called once per chunker instance since the iterator
+ * will mutate internal state of the chunker.
+ *
+ * @param [in] chunker A `PARCChunker` instance.
+ *
+ * @return a `PARCIterator` that traverses the chunks of the underlying data.
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCChunker *chunker = ...
+ *
+ * PARCIterator *itr = parcChunker_ReverseIterator(chunker);
+ *
+ * // use the iterator to traverse the chunker
+ * }
+ * @endcode
+ */
+PARCIterator *parcChunker_ReverseIterator(const PARCChunker *chunker);
+
+/**
+ * Get the chunk size of a `PARCChunker.`
+ *
+ * @param [in] chunker A `PARCChunker` instance.
+ *
+ * @return the chunk size
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCChunker *chunker = ...
+ *
+ * size_t chunkSize = parcChunker_GetChunkSize(chunker);
+ * }
+ * @endcode
+ */
+size_t parcChunker_GetChunkSize(const PARCChunker *chunker);
+#endif // libparc_parc_Chunker_h
diff --git a/libparc/parc/algol/parc_Clock.c b/libparc/parc/algol/parc_Clock.c
new file mode 100755
index 00000000..95cf74bc
--- /dev/null
+++ b/libparc/parc/algol/parc_Clock.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 <time.h>
+#include <parc/algol/parc_Clock.h>
+
+#if __APPLE__
+#include <mach/mach.h>
+#include <mach/clock.h>
+#include <mach/mach_time.h>
+#endif
+
+// These are used by the counter Clock
+#include <parc/algol/parc_AtomicInteger.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+// ----
+
+typedef struct counter_clock {
+ uint64_t counter;
+} _CounterClock;
+
+parcObject_ExtendPARCObject(_CounterClock, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+static parcObject_ImplementAcquire(_counterClock, _CounterClock);
+
+static PARCClock *
+_counterClock_AcquireInterface(const PARCClock *clock)
+{
+ _CounterClock *cc = (_CounterClock *) clock->closure;
+ _counterClock_Acquire(cc);
+ return (PARCClock *) clock;
+}
+
+static void
+_counterClock_ReleaseInterface(PARCClock **clockPtr)
+{
+ PARCClock *clock = *clockPtr;
+ _CounterClock *cc = (_CounterClock *) clock->closure;
+
+ PARCReferenceCount refcount = parcObject_Release((void **) &cc);
+ if (refcount == 0) {
+ parcMemory_Deallocate((void **) clockPtr);
+ } else {
+ *clockPtr = NULL;
+ }
+}
+
+static void
+_counterClock_GetTimeval(const PARCClock *clock, struct timeval *output)
+{
+ _CounterClock *cc = (_CounterClock *) clock->closure;
+ uint64_t value = parcAtomicInteger_Uint64Increment(&cc->counter);
+
+ // put 19 bits in the micro-seconds so it is never larger than 1E+6
+ output->tv_sec = value >> 19;
+ output->tv_usec = value & 0x7FFFF;
+}
+
+static uint64_t
+_counterClock_GetTime(const PARCClock *clock)
+{
+ _CounterClock *cc = (_CounterClock *) clock->closure;
+ return parcAtomicInteger_Uint64Increment(&cc->counter);
+}
+
+PARCClock *
+parcClock_Counter(void)
+{
+ _CounterClock *cc = parcObject_CreateInstance(_CounterClock);
+ cc->counter = 0;
+
+ PARCClock *clock = parcMemory_Allocate(sizeof(PARCClock));
+ clock->closure = cc;
+ clock->acquire = _counterClock_AcquireInterface;
+ clock->release = _counterClock_ReleaseInterface;
+ clock->getTime = _counterClock_GetTime;
+ clock->getTimeval = _counterClock_GetTimeval;
+ return clock;
+}
+
+// ===========
+// Wallclock
+
+static void
+_wallclock_GetTimeval(const PARCClock *dummy __attribute__((unused)), struct timeval *output)
+{
+#if __linux__
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ output->tv_sec = ts.tv_sec;
+ output->tv_usec = ts.tv_nsec / 1000;
+#else
+ clock_serv_t clockService;
+ mach_timespec_t mts;
+
+ host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clockService);
+ clock_get_time(clockService, &mts);
+ mach_port_deallocate(mach_task_self(), clockService);
+
+ output->tv_sec = mts.tv_sec;
+ output->tv_usec = mts.tv_nsec / 1000;
+#endif
+}
+
+static uint64_t
+_wallclock_GetTime(const PARCClock *clock)
+{
+ struct timeval tv;
+ _wallclock_GetTimeval(clock, &tv);
+ uint64_t t = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+
+ return t;
+}
+
+
+static PARCClock *
+_wallclock_Acquire(const PARCClock *clock)
+{
+ return (PARCClock *) clock;
+}
+
+static void
+_wallclock_Release(PARCClock **clockPtr)
+{
+ *clockPtr = NULL;
+}
+
+static PARCClock _wallclock = {
+ .closure = NULL,
+ .getTime = _wallclock_GetTime,
+ .getTimeval = _wallclock_GetTimeval,
+ .acquire = _wallclock_Acquire,
+ .release = _wallclock_Release
+};
+
+PARCClock *
+parcClock_Wallclock(void)
+{
+ return &_wallclock;
+}
+
+
+// ==========================
+// Monotonic clock
+
+static void
+_monoclock_GetTimeval(const PARCClock *dummy __attribute__((unused)), struct timeval *output)
+{
+#if __linux__
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+ output->tv_sec = ts.tv_sec;
+ output->tv_usec = ts.tv_nsec / 1000;
+#else
+ clock_serv_t clockService;
+ mach_timespec_t mts;
+
+ host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &clockService);
+ clock_get_time(clockService, &mts);
+ mach_port_deallocate(mach_task_self(), clockService);
+
+ output->tv_sec = mts.tv_sec;
+ output->tv_usec = mts.tv_nsec / 1000;
+#endif
+}
+
+static uint64_t
+_monoclock_GetTime(const PARCClock *clock)
+{
+ struct timeval tv;
+ _monoclock_GetTimeval(clock, &tv);
+ uint64_t t = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+
+ return t;
+}
+
+static PARCClock *
+_monoclock_Acquire(const PARCClock *clock)
+{
+ return (PARCClock *) clock;
+}
+
+static void
+_monoclock_Release(PARCClock **clockPtr)
+{
+ *clockPtr = NULL;
+}
+
+static PARCClock _monoclock = {
+ .closure = NULL,
+ .getTime = _monoclock_GetTime,
+ .getTimeval = _monoclock_GetTimeval,
+ .acquire = _monoclock_Acquire,
+ .release = _monoclock_Release
+};
+
+PARCClock *
+parcClock_Monotonic(void)
+{
+ return &_monoclock;
+}
+
+// ===========================
+// Facade API
+
+uint64_t
+parcClock_GetTime(const PARCClock *clock)
+{
+ return clock->getTime(clock);
+}
+
+void
+parcClock_GetTimeval(const PARCClock *clock, struct timeval *output)
+{
+ clock->getTimeval(clock, output);
+}
+
+PARCClock *
+parcClock_Acquire(const PARCClock *clock)
+{
+ return clock->acquire(clock);
+}
+
+void
+parcClock_Release(PARCClock **clockPtr)
+{
+ (*clockPtr)->release(clockPtr);
+}
+
diff --git a/libparc/parc/algol/parc_Clock.h b/libparc/parc/algol/parc_Clock.h
new file mode 100755
index 00000000..35c77fd7
--- /dev/null
+++ b/libparc/parc/algol/parc_Clock.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 parc_Clock.h
+ * @ingroup datastructures
+ * @brief Generic API to a clock
+ *
+ * Interface over clock providers. We provide two system clocks, a Wallclock that tracks the
+ * real time clock and a monotonic clock that will not skew or go backwards.
+ * @see parcClock_Monotonic()
+ * and
+ * @see parcClock_Wallclock()
+ * Also provided is a counting clock.
+ * @see parcClock_Counter()
+ *
+ * Below is a complete example of a simple custom clock that implements an atomic counter for
+ * the time. Each call to getTime or getTimeval will increment the counter. This clock is
+ * available as parcClock_Counter().
+ *
+ * @code
+ * typedef struct counter_clock {
+ * uint64_t counter;
+ * } _CounterClock;
+ *
+ * parcObject_ExtendPARCObject(_CounterClock, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ * static parcObject_ImplementAcquire(_counterClock, _CounterClock);
+ *
+ * static PARCClock *
+ * _counterClock_AcquireInterface(const PARCClock *clock)
+ * {
+ * _CounterClock *cc = (_CounterClock *) clock->closure;
+ * _counterClock_Acquire(cc);
+ * return (PARCClock *) clock;
+ * }
+ *
+ * static void
+ * _counterClock_ReleaseInterface(PARCClock **clockPtr)
+ * {
+ * PARCClock *clock = *clockPtr;
+ * _CounterClock *cc = (_CounterClock *) clock->closure;
+ *
+ * PARCReferenceCount refcount = parcObject_Release((void **) &cc);
+ * if (refcount == 0) {
+ * parcMemory_Deallocate((void **) clockPtr);
+ * } else {
+ * *clockPtr = NULL;
+ * }
+ * }
+ *
+ * static void
+ * _counterClock_GetTimeval(const PARCClock *clock, struct timeval *output)
+ * {
+ * _CounterClock *cc = (_CounterClock *) clock->closure;
+ * uint64_t value = parcAtomicInteger_Uint64Increment(&cc->counter);
+ * // put 19 bits in the micro-seconds so it is never larger than 1E+6
+ * output->tv_sec = value >> 19;
+ * output->tv_usec = value & 0x7FFFF;
+ * }
+ *
+ * static uint64_t
+ * _counterClock_GetTime(const PARCClock *clock)
+ * {
+ * _CounterClock *cc = (_CounterClock *) clock->closure;
+ * return parcAtomicInteger_Uint64Increment(&cc->counter);
+ * }
+ *
+ * PARCClock *
+ * parcClock_Counter(void)
+ * {
+ * _CounterClock *cc = parcObject_CreateInstance(_CounterClock);
+ * cc->counter = 0;
+ *
+ * PARCClock *clock = parcMemory_Allocate(sizeof(PARCClock));
+ * clock->closure = cc;
+ * clock->acquire = _counterClock_AcquireInterface;
+ * clock->release = _counterClock_ReleaseInterface;
+ * clock->getTime = _counterClock_GetTime;
+ * clock->getTimeval = _counterClock_GetTimeval;
+ * return clock;
+ * }
+ * @encode
+ *
+ */
+
+#ifndef PARC_parc_Clock_h
+#define PARC_parc_Clock_h
+
+#include <inttypes.h>
+#include <sys/time.h>
+
+struct parc_clock;
+typedef struct parc_clock PARCClock;
+
+struct parc_clock {
+ /**
+ * Opaque parameter set by the clock provider
+ */
+ void *closure;
+
+ /**
+ * Gets the clock time
+ *
+ * The resolution and epoch of the clock are determined by the clock provider
+ *
+ * @param [in] clock An allocated PARCClock
+ *
+ * @retval number The clock's time as a uint64_t
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Monotonic();
+ * uint64_t t = parcClock_GetTime(clock);
+ * parcClock_Release(&clock);
+ * }
+ * @endcode
+ */
+ uint64_t (*getTime)(const PARCClock *clock);
+
+ /**
+ * Gets the clock time as a struct timeval
+ *
+ * The resolution and epoch of the clock are determined by the clock provider.
+ * There may be an arbitrary mapping to the struct timeval as per the clock
+ * provider, so the units of 'seconds' and 'micro seconds' need to be interpreted
+ * as per the clock provider.
+ *
+ * @param [in] clock An allocated PARCClock
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ void (*getTimeval)(const PARCClock *clock, struct timeval *output);
+
+ /**
+ * Increase the number of references to a `PARCClock`.
+ *
+ * Note that new `PARCClock` is not created,
+ * only that the given `PARCClock` reference count is incremented.
+ * Discard the reference by invoking `parcClock_Release`.
+ *
+ * @param [in] clock A pointer to a `PARCClock` instance.
+ *
+ * @return The input `PARCClock` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Counter();
+ * PARCClock *copy = parcClock_Acquire(clock);
+ * parcClock_Release(&copy);
+ * parcClock_Release(&clock);
+ *
+ * }
+ * @endcode
+ */
+ PARCClock * (*acquire)(const PARCClock *clock);
+
+ /**
+ * 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] clockPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Counter();
+ * PARCClock *copy = parcClock_Acquire(clock);
+ * parcClock_Release(&copy);
+ * parcClock_Release(&clock);
+ *
+ * }
+ * @endcode
+ */
+
+ void (*release)(PARCClock **clockPtr);
+};
+
+/**
+ * A clock provider for the wall clock time
+ *
+ * This will use clock_gettime(CLOCK_REALTIME_COARSE) on linux or
+ * host_get_clock_service with CALENDAR_CLOCK on Mac
+ *
+ * @retval non-null An allocated PARCClock, which must be released via parcClock_Release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Wallclock();
+ * uint64_t t = parcClock_GetTime(clock);
+ * parcClock_Release(&clock);
+ * }
+ * @endcode
+ */
+PARCClock *parcClock_Wallclock(void);
+
+/**
+ * A monotonic clock that will not normally adjust for time changes
+ *
+ * On linux, this uses the CLOCK_MONOTONIC_RAW. On Darwin, it uses
+ * the SYSTEM_CLOCK from <mach/mach_time.h>.
+ *
+ * @retval non-null An allocated PARCClock, which must be released via parcClock_Release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Monotonic();
+ * uint64_t t = parcClock_GetTime(clock);
+ * parcClock_Release(&clock);
+ * }
+ * @endcode
+ */
+PARCClock *parcClock_Monotonic(void);
+
+
+/**
+ * The counter clock begins at 0 and increments for every call to getTime or getTimeval
+ *
+ * Each allocated counter clock will begin at zero. Copies made via parcClock_Acquire() will
+ * share the same counter and use atomic updates.
+ *
+ * getTime() will return the counter.
+ *
+ * getTimeval() will return the lower 19 bits in tv_usec (so it does not overflow the concept
+ * of micro-second) and the upper 45 bits are in tv_sec. On some platforms, that may overflow.
+ *
+ * @retval non-null An allocated PARCClock, which must be released via parcClock_Release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Counter();
+ * uint64_t t = parcClock_GetTime(clock);
+ * parcClock_Release(&clock);
+ * }
+ * @endcode
+ */
+PARCClock *parcClock_Counter(void);
+
+/**
+ * Returns the clock provider's idea of the current time as a uint64
+ *
+ * Returns the clock provider's idea of the current time, which may or
+ * may not be a wall clock time.
+ *
+ * @param [in] clock A clock provider
+ *
+ * @retval number The current time (depends on provider)
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Counter();
+ * uint64_t t = parcClock_GetTime(clock);
+ * parcClock_Release(&clock);
+ * }
+ * @endcode
+ */
+uint64_t parcClock_GetTime(const PARCClock *clock);
+
+/**
+ * Returns the clock provider's idea of the current time as a timeval
+ *
+ * Returns the clock provider's idea of the current time, which may or
+ * may not be a wall clock time.
+ *
+ * @param [in] clock A clock provider
+ * @param [in] output The structure to fill in with the current time
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval t;
+ * PARCClock *clock = parcClock_Counter();
+ * parcClock_GetTimeval(clock, &t);
+ * parcClock_Release(&clock);
+ * }
+ * @endcode
+ */
+void parcClock_GetTimeval(const PARCClock *clock, struct timeval *output);
+
+/**
+ * Increase the number of references to a `PARCClock`.
+ *
+ * Note that new `PARCClock` is not created,
+ * only that the given `PARCClock` reference count is incremented.
+ * Discard the reference by invoking `parcClock_Release`.
+ *
+ * @param [in] clock A pointer to a `PARCClock` instance.
+ *
+ * @return The input `PARCClock` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Counter();
+ * PARCClock *copy = parcClock_Acquire(clock);
+ * parcClock_Release(&copy);
+ * parcClock_Release(&clock);
+ *
+ * }
+ * @endcode
+ */
+PARCClock *parcClock_Acquire(const PARCClock *clock);
+
+/**
+ * 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] clockPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCClock *clock = parcClock_Counter();
+ * PARCClock *copy = parcClock_Acquire(clock);
+ * parcClock_Release(&copy);
+ * parcClock_Release(&clock);
+ *
+ * }
+ * @endcode
+ */
+void parcClock_Release(PARCClock **clockPtr);
+#endif // PARC_parc_Clock_h
diff --git a/libparc/parc/algol/parc_Collection.h b/libparc/parc/algol/parc_Collection.h
new file mode 100755
index 00000000..87deff12
--- /dev/null
+++ b/libparc/parc/algol/parc_Collection.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Collection.h
+ * @ingroup datastructures
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+#ifndef libparc_parc_Collection_h
+#define libparc_parc_Collection_h
+
+struct parc_collection;
+typedef struct parc_collection PARCCollection;
+#endif // libparc_parc_Collection_h
diff --git a/libparc/parc/algol/parc_Deque.c b/libparc/parc/algol/parc_Deque.c
new file mode 100644
index 00000000..4793b032
--- /dev/null
+++ b/libparc/parc/algol/parc_Deque.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <sys/queue.h>
+
+#include <parc/algol/parc_Deque.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+PARCListInterface *PARCDequeAsPARCList = &(PARCListInterface) {
+ .Add = (bool (*)(void *, void *))parcDeque_Append,
+ .AddAtIndex = (void (*)(void *, int index, void *))NULL,
+ .AddCollection = (bool (*)(void *, PARCCollection *))NULL,
+ .AddCollectionAtIndex = (bool (*)(void *, int index, PARCCollection *))NULL,
+ .Clear = (void (*)(void *))NULL,
+ .Contains = (bool (*)(const void *, const PARCObject *))NULL,
+ .ContainsCollection = (bool (*)(const void *, const PARCCollection *))NULL,
+ .Copy = (void * (*)(const PARCList *))parcDeque_Copy,
+ .Destroy = (void (*)(void **))parcDeque_Release,
+ .Equals = (bool (*)(const void *, const void *))parcDeque_Equals,
+ .GetAtIndex = (void * (*)(const void *, size_t))parcDeque_GetAtIndex,
+ .HashCode = (PARCHashCode (*)(const void *))NULL,
+ .IndexOf = (size_t (*)(const void *, const PARCObject *element))NULL,
+ .IsEmpty = (bool (*)(const void *))parcDeque_IsEmpty,
+ .LastIndexOf = (size_t (*)(void *, const PARCObject *element))NULL,
+ .Remove = (bool (*)(void *, const PARCObject *element))NULL,
+ .RemoveAtIndex = (void * (*)(PARCList *, size_t))NULL,
+ .RemoveCollection = (bool (*)(void *, const PARCCollection *))NULL,
+ .RetainCollection = (bool (*)(void *, const PARCCollection *))NULL,
+ .SetAtIndex = (void * (*)(void *, size_t index, void *))NULL,
+ .Size = (size_t (*)(const void *))parcDeque_Size,
+ .SubList = (PARCList * (*)(const void *, size_t, size_t))NULL,
+ .ToArray = (void** (*)(const void *))NULL,
+};
+
+struct parc_deque_node {
+ void *element;
+ struct parc_deque_node *previous;
+ struct parc_deque_node *next;
+};
+
+struct parc_deque {
+ PARCObjectDescriptor object;
+ struct parc_deque_node *head;
+ struct parc_deque_node *tail;
+ size_t size;
+};
+
+static void *
+_defaultElementCopy(const void *x)
+{
+ return (void *) x;
+}
+
+static bool
+_defaultElementEquals(const void *x, const void *y)
+{
+ return (x == y);
+}
+
+static inline struct parc_deque_node *
+_parcDequeNode_Create(void *element, struct parc_deque_node *previous, struct parc_deque_node *next)
+{
+ struct parc_deque_node *result = parcMemory_Allocate(sizeof(struct parc_deque_node));
+ if (result != NULL) {
+ result->element = element;
+ result->next = next;
+ result->previous = previous;
+ }
+
+ return result;
+}
+
+static void
+_parcDequeNode_Destroy(PARCDeque *deque __attribute__((unused)), struct parc_deque_node **nodePtr)
+{
+ struct parc_deque_node *node = *nodePtr;
+
+ parcMemory_Deallocate((void **) &node);
+ *nodePtr = 0;
+}
+
+static void
+_parcDequeNode_AssertInvariants(struct parc_deque_node *node)
+{
+ assertNotNull(node, "Expected non-null node pointer.");
+ if (node->next != NULL) {
+ assertTrue(node->next->previous == node, "Expected next node to point to this node.");
+ }
+ if (node->previous != NULL) {
+ assertTrue(node->previous->next == node, "Expected previous node to point to this node.");
+ }
+}
+
+static void
+_parcDeque_AssertInvariants(const PARCDeque *deque)
+{
+ assertNotNull(deque, "Parameter cannot be null.");
+ if (deque->head != NULL) {
+ assertTrue(deque->size != 0, "PARCDeque head is not-null, but size is zero.");
+ assertNotNull(deque->tail, "PARCDeque head is not-null, but tail is null.");
+ _parcDequeNode_AssertInvariants(deque->head);
+ _parcDequeNode_AssertInvariants(deque->tail);
+ } else {
+ assertNull(deque->tail, "PARCDeque head is null, but tail is not null.");
+ assertTrue(deque->size == 0, "PARCDeque head is null, but size is not zero.");
+ }
+}
+
+static void
+_parcDeque_Destroy(PARCDeque **dequePtr)
+{
+ PARCDeque *deque = *dequePtr;
+
+ struct parc_deque_node *next = NULL; //deque->head;
+
+ for (struct parc_deque_node *node = deque->head; node != NULL; node = next) {
+ next = node->next;
+ _parcDequeNode_Destroy(deque, &node);
+ }
+}
+
+static struct parc_deque_node *
+_parcDequeNode_Init(PARCDeque *deque __attribute__((unused)))
+{
+ return NULL;
+}
+
+static bool
+_parcDequeNode_Fini(PARCDeque *deque __attribute__((unused)), const struct parc_deque_node *node __attribute__((unused)))
+{
+ return true;
+}
+
+static struct parc_deque_node *
+_parcDequeNode_Next(PARCDeque *deque __attribute__((unused)), const struct parc_deque_node *node)
+{
+ if (node == NULL) {
+ return deque->head;
+ }
+ trapOutOfBoundsIf(node->next == NULL, "No more elements.");
+ return node->next;
+}
+
+static bool
+_parcDequeNode_HasNext(PARCDeque *deque __attribute__((unused)), const struct parc_deque_node *node)
+{
+ if (node == NULL) {
+ return (deque->head != NULL);
+ }
+ return (node->next != NULL);
+}
+
+static void *
+_parcDequeNode_Element(PARCDeque *deque __attribute__((unused)), const struct parc_deque_node *node)
+{
+ return node->element;
+}
+
+parcObject_ExtendPARCObject(PARCDeque, _parcDeque_Destroy, parcDeque_Copy, NULL, parcDeque_Equals, NULL, NULL, NULL);
+
+static PARCDeque *
+_create(const PARCObjectDescriptor *interface)
+{
+ PARCDeque *result = parcObject_CreateInstance(PARCDeque);
+
+ if (result != NULL) {
+ result->object = *interface;
+ result->head = NULL;
+ result->tail = NULL;
+ result->size = 0;
+ }
+ return result;
+}
+
+PARCIterator *
+parcDeque_Iterator(PARCDeque *deque)
+{
+ PARCIterator *iterator = parcIterator_Create(deque,
+ (void *(*)(PARCObject *))_parcDequeNode_Init,
+ (bool (*)(PARCObject *, void *))_parcDequeNode_HasNext,
+ (void *(*)(PARCObject *, void *))_parcDequeNode_Next,
+ NULL,
+ (void *(*)(PARCObject *, void *))_parcDequeNode_Element,
+ (void (*)(PARCObject *, void *))_parcDequeNode_Fini,
+ NULL);
+
+ return iterator;
+}
+
+PARCDeque *
+parcDeque_Create(void)
+{
+ static PARCObjectDescriptor defaultObjectInterface = {
+ .destroy = (PARCObjectDestroy *) NULL,
+ .copy = (PARCObjectCopy *) _defaultElementCopy,
+ .toString = (PARCObjectToString *) NULL,
+ .equals = (PARCObjectEquals *) _defaultElementEquals,
+ .compare = (PARCObjectCompare *) NULL
+ };
+ return _create(&defaultObjectInterface);
+}
+
+PARCDeque *
+parcDeque_CreateObjectInterface(const PARCObjectDescriptor *interface)
+{
+ return _create(interface);
+}
+
+PARCDeque *
+parcDeque_CreateCustom(bool (*elementEquals)(const void *, const void *), void *(*elementCopy)(const void *))
+{
+ PARCObjectDescriptor objectInterface;
+ parcObject_MetaInitialize(&objectInterface);
+
+ objectInterface.equals = elementEquals != NULL ? elementEquals : _defaultElementEquals;
+ objectInterface.copy = elementCopy != NULL ? elementCopy : _defaultElementCopy;
+
+ return _create(&objectInterface);
+}
+
+parcObject_ImplementAcquire(parcDeque, PARCDeque);
+
+parcObject_ImplementRelease(parcDeque, PARCDeque);
+
+PARCDeque *
+parcDeque_Copy(const PARCDeque *deque)
+{
+ PARCDeque *result = _create(&deque->object);
+
+ struct parc_deque_node *node = deque->head;
+
+ while (node != NULL) {
+ parcDeque_Append(result, deque->object.copy(node->element));
+ node = node->next;
+ }
+
+ return result;
+}
+
+PARCDeque *
+parcDeque_Append(PARCDeque *deque, void *element)
+{
+ struct parc_deque_node *node = _parcDequeNode_Create(element, deque->tail, NULL);
+
+ if (deque->tail == NULL) {
+ deque->tail = node;
+ } else {
+ deque->tail->next = node;
+ deque->tail = node;
+ }
+
+ if (deque->head == NULL) {
+ deque->head = deque->tail;
+ }
+
+ deque->size++;
+
+ return deque;
+}
+
+PARCDeque *
+parcDeque_Prepend(PARCDeque *deque, void *element)
+{
+ struct parc_deque_node *node = _parcDequeNode_Create(element, NULL, deque->head);
+
+ if (deque->head == NULL) {
+ deque->head = node;
+ } else {
+ deque->head->previous = node;
+ deque->head = node;
+ }
+
+ if (deque->tail == NULL) {
+ deque->tail = deque->head;
+ }
+ deque->size++;
+
+ _parcDequeNode_AssertInvariants(node);
+ _parcDeque_AssertInvariants(deque);
+
+ return deque;
+}
+
+void *
+parcDeque_RemoveFirst(PARCDeque *deque)
+{
+ void *result = NULL;
+
+ if (deque->head != NULL) {
+ struct parc_deque_node *node = deque->head;
+ result = node->element;
+ if (deque->head == deque->tail) {
+ deque->head = NULL;
+ deque->tail = NULL;
+ } else {
+ deque->head = node->next;
+ deque->head->previous = NULL;
+ }
+ parcMemory_Deallocate((void **) &node);
+ deque->size--;
+ }
+
+ _parcDeque_AssertInvariants(deque);
+
+ return result;
+}
+
+void *
+parcDeque_RemoveLast(PARCDeque *deque)
+{
+ void *result = NULL;
+
+ if (deque->tail != NULL) {
+ struct parc_deque_node *node = deque->tail;
+ deque->tail = node->previous;
+ deque->tail->next = NULL;
+
+ result = node->element;
+ parcMemory_Deallocate((void **) &node);
+ deque->size--;
+ }
+
+ _parcDeque_AssertInvariants(deque);
+ return result;
+}
+
+void *
+parcDeque_PeekFirst(const PARCDeque *deque)
+{
+ void *result = NULL;
+
+ if (deque->head != NULL) {
+ struct parc_deque_node *node = deque->head;
+ result = node->element;
+ }
+ return result;
+}
+
+void *
+parcDeque_PeekLast(const PARCDeque *deque)
+{
+ void *result = NULL;
+
+ if (deque->tail != NULL) {
+ struct parc_deque_node *node = deque->tail;
+ result = node->element;
+ }
+ return result;
+}
+
+size_t
+parcDeque_Size(const PARCDeque *deque)
+{
+ return deque->size;
+}
+
+bool
+parcDeque_IsEmpty(const PARCDeque *deque)
+{
+ return (parcDeque_Size(deque) == 0);
+}
+
+void *
+parcDeque_GetAtIndex(const PARCDeque *deque, size_t index)
+{
+ if (index > (parcDeque_Size(deque) - 1)) {
+ trapOutOfBounds(index, "[0, %zd]", parcDeque_Size(deque) - 1);
+ }
+ struct parc_deque_node *node = deque->head;
+ while (index--) {
+ node = node->next;
+ }
+
+ return node->element;
+}
+
+bool
+parcDeque_Equals(const PARCDeque *x, const PARCDeque *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ if (x->object.equals == y->object.equals) {
+ if (x->size == y->size) {
+ struct parc_deque_node *xNode = x->head;
+ struct parc_deque_node *yNode = y->head;
+
+ while (xNode != NULL) {
+ if (x->object.equals(xNode->element, yNode->element) == false) {
+ return false;
+ }
+ xNode = xNode->next;
+ yNode = yNode->next;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+parcDeque_Display(const PARCDeque *deque, const int indentation)
+{
+ if (deque == NULL) {
+ parcDisplayIndented_PrintLine(indentation, "PARCDeque@NULL");
+ } else {
+ parcDisplayIndented_PrintLine(indentation, "PARCDeque@%p {", (void *) deque);
+
+ struct parc_deque_node *node = deque->head;
+
+ while (node != NULL) {
+ parcDisplayIndented_PrintLine(indentation + 1,
+ ".previous=%11p, %11p=%11p, .next=%11p",
+ node->previous, node, node->element, node->next);
+ node = node->next;
+ }
+
+ parcDisplayIndented_PrintLine(indentation, "}\n");
+ }
+}
diff --git a/libparc/parc/algol/parc_Deque.h b/libparc/parc/algol/parc_Deque.h
new file mode 100755
index 00000000..3e11e845
--- /dev/null
+++ b/libparc/parc/algol/parc_Deque.h
@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Deque.h
+ * @ingroup datastructures
+ * @brief PARC Double-ended Queue (Deque)
+ *
+ *
+ */
+#ifndef libparc_parc_Deque_h
+#define libparc_parc_Deque_h
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Iterator.h>
+
+struct parc_deque;
+/**
+ * A double-ended queue.
+ *
+ * @see {@link parcDeque_Create}
+ * @see {@link parcDeque_CreateCustom}
+ */
+typedef struct parc_deque PARCDeque;
+
+/**
+ * Create a `PARCDeque` instance with the default element equality and copy functions.
+ *
+ * The queue is created with no elements.
+ *
+ * The default element equals function is used by the `{@link parcDeque_Equals} function and
+ * simply compares the values using the `==` operator.
+ * Users that need more sophisticated comparisons of the elements need to supply their own
+ * function via the {@link parcDeque_CreateCustom} function.
+ *
+ * @return non-NULL A pointer to a `PARCDeque` instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+PARCDeque *parcDeque_Create(void);
+
+PARCIterator *parcDeque_Iterator(PARCDeque *deque);
+
+/**
+ * Create a PARCDeque instance that uses the {@link PARCObjectDescriptor} providing functions for element equality and copy function.
+ *
+ * The queue is created with no elements.
+ *
+ * @param [in] interface A pointer to a `PARCObjectDescriptor` instance.
+ *
+ * @return non-NULL A pointer to a `PARCDeque` instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCDeque *parcDeque_CreateObjectInterface(const PARCObjectDescriptor *interface);
+
+/**
+ * Create a `PARCDeque` instance with a custom element equality and copy function.
+ *
+ * The queue is created with no elements.
+ *
+ * The supplied element equals function is used by the `parcDeque_Equals`
+ * function which must return `true` if the elements are equal, and `false` if unequal.
+ *
+ * @param [in] elementEquals The function to be used for equals
+ * @param [in] elementCopy The function to be used for copy
+ *
+ * @return non-NULL A pointer to a `PARCDeque` instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see {@link parcDeque_CreateObjectInterface}
+ */
+PARCDeque *parcDeque_CreateCustom(bool (*elementEquals)(const void *, const void *), void *(*elementCopy)(const void *));
+
+/**
+ * Acquire a new reference to an instance of `PARCDeque`.
+ *
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] deque The instance of `PARCDeque` to which to refer.
+ *
+ * @return The same value as the input parameter @p deque
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCDeque *parcDeque_Acquire(const PARCDeque *deque);
+
+/**
+ * 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 interface will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] dequePtr A pointer to a pointer to the instance of `PARCDeque` to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDeque *buffer = parcDeque_Create(10);
+ *
+ * parcDeque_Release(&buffer);
+ * }
+ * @endcode
+ */
+void parcDeque_Release(PARCDeque **dequePtr);
+
+/**
+ * Copy a a `PARCDeque` to another.
+ *
+ * @param [in] deque A pointer to an instance of `PARCDeque`
+ *
+ * @return A pointer to a copy of the original instance of `PARCDeque`
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCDeque *parcDeque_Copy(const PARCDeque *deque);
+
+/**
+ * Append an element to the tail end of the specified `PARCDeque`
+ *
+ * @param [in,out] deque A pointer to the instance of `PARCDeque` to which the element will be appended
+ * @param [in] element A pointer to the element to be appended to the instance of `PARCDeque`
+ *
+ * @return non NULL A pointer to the specific instance of `PARCDeque`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCDeque *parcDeque_Append(PARCDeque *deque, void *element);
+
+/**
+ * Prepend an element to the head end of the specified `PARCDeque`
+ *
+ *
+ * @param [in,out] deque A pointer to the instance of `PARCDeque` to which the element will be prepended
+ * @param [in] element A pointer to the element to be appended to the instance of `PARCDeque`
+ *
+ * @return non NULL A pointer to the specific instance of `PARCDeque`
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCDeque *parcDeque_Prepend(PARCDeque *deque, void *element);
+
+/**
+ * Return the first element of the specified `PARCDeque` and remove it from the queue
+ *
+ * @param [in,out] deque A pointer to the instance of `PARCDeque` from which the first element will be returned and removed
+ *
+ * @return non NULL A pointer to the element removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+void *parcDeque_RemoveFirst(PARCDeque *deque);
+
+/**
+ * Return the last element of the specified `PARCDeque` and remove it from the queue
+ *
+ * @param [in,out] deque A pointer to the instance of `PARCDeque` from which the last element will be returned and removed
+ *
+ * @return non NULL A pointer to the element removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+void *parcDeque_RemoveLast(PARCDeque *deque);
+
+/**
+ * Return the first element of the specified `PARCDeque` but do NOT remove it from the queue
+ *
+ * @param [in] deque A pointer to the instance of `PARCDeque` from which the first element will be returned
+ *
+ * @return non NULL A pointer to the first element
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+void *parcDeque_PeekFirst(const PARCDeque *deque);
+
+/**
+ * Return the last element of the specified `PARCDeque` but do NOT remove it from the queue
+ *
+ * @param [in] deque A pointer to the instance of `PARCDeque` from which the last element will be returned
+ *
+ * @return non NULL A pointer to the last element
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+void *parcDeque_PeekLast(const PARCDeque *deque);
+
+/**
+ * Return the size of the specified queue
+ *
+ * @param [in] deque A pointer to the instance of `PARCDeque`
+ *
+ * @return `size_t` The size of the queue
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+size_t parcDeque_Size(const PARCDeque *deque);
+
+/**
+ * Return True if the `PARCDeque` is empty or False if not.
+ *
+ * @param [in] deque A pointer to the instance of `PARCDeque`
+ *
+ * @return bool True if the `PARCDeque` is empty or False if not.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+bool parcDeque_IsEmpty(const PARCDeque *deque);
+
+/**
+ * Get a pointer to the specified element.
+ *
+ * @param [in] deque A pointer to a `PARCDeque` instance.
+ * @param [in] index The index of the element to be retrieved.
+ *
+ * @throws `trapOutOfBounds`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+void *parcDeque_GetAtIndex(const PARCDeque *deque, size_t index);
+
+/**
+ * Determine if two `PARCDeque` instances are equal.
+ *
+ * This function implements the following equivalence relations on non-null `PARCDeque` instances:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcDeque_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcDeque_Equals(x, y)` must return true if and only if
+ * `parcDeque_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcDeque_Equals(x, y)` returns true and
+ * `parcDeque_Equals(y, z)` returns true,
+ * then `parcDeque_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcDeque_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcDeque_Equals(x, NULL)` must return false.
+ *
+ * Two `PARCDeque` instances with different element equality functions are always unequal.
+ *
+ * @param [in] x A pointer to a `PARCDeque` instance.
+ * @param [in] y A pointer to a `PARCDeque` instance.
+ *
+ * @return true `PARCDeque` x and y are equal.
+ * @return false `PARCDeque` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcDeque_Equals(const PARCDeque *x, const PARCDeque *y);
+
+/**
+ * Print a human readable representation of the given `PARCDeque`.
+ *
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ * @param [in] deque A pointer to the instance to display.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDeque *instance = parcDeque_Create();
+ *
+ * parcDeque_Display(instance, 0);
+ *
+ * parcDeque_Release(&instance);
+ * }
+ * @endcode
+ *
+ */
+void parcDeque_Display(const PARCDeque *deque, int indentation);
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcDeque_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] object A pointer to a valid PARCDeque instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcDeque_Notify(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotify(parcDeque, PARCDeque);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the parcDeque_Notify() function on the same object.
+ * *
+ * @param [in] object A pointer to a valid `PARCDeque` instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcDeque_Wait(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementWait(parcDeque, PARCDeque);
+
+/**
+ * Obtain the lock on the given `PARCDeque` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] object A pointer to a valid `PARCDeque` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, or the `PARCDeque` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcDeque_Lock(object)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementLock(parcDeque, PARCDeque);
+
+/**
+ * Try to obtain the advisory lock on the given PARCDeque instance.
+ *
+ * Once the lock is obtained, the caller must release the lock as soon as possible.
+ *
+ * @param [in] object A pointer to a valid PARCDeque instance.
+ *
+ * @return true The PARCDeque is locked.
+ * @return false The PARCDeque is unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcDeque_TryLock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementTryLock(parcDeque, PARCDeque);
+
+/**
+ * Try to unlock the advisory lock on the given `PARCDeque` instance.
+ *
+ * @param [in] object A pointer to a valid `PARCDeque` instance.
+ *
+ * @return true The `PARCDeque` was locked and now is unlocked.
+ * @return false The `PARCDeque` was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcDeque_Unlock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementUnlock(parcDeque, PARCDeque);
+
+/**
+ * Determine if the advisory lock on the given `PARCDeque` instance is locked.
+ *
+ * @param [in] object A pointer to a valid `PARCDeque` instance.
+ *
+ * @return true The `PARCDeque` is locked.
+ * @return false The `PARCDeque` is unlocked.
+ * Example:
+ * @code
+ * {
+ * if (parcDeque_IsLocked(object)) {
+ * ...
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementIsLocked(parcDeque, PARCDeque);
+
+#endif // libparc_parc_Deque_h
diff --git a/libparc/parc/algol/parc_Dictionary.c b/libparc/parc/algol/parc_Dictionary.c
new file mode 100755
index 00000000..628b08e2
--- /dev/null
+++ b/libparc/parc/algol/parc_Dictionary.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <string.h>
+
+#include <parc/algol/parc_Dictionary.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_TreeRedBlack.h>
+
+struct parc_dictionary {
+ PARCDictionary_CompareKey keyCompareFunction;
+ PARCDictionary_KeyHashFunc keyHashFunction;
+ PARCDictionary_FreeKey keyFreeFunction;
+ PARCDictionary_FreeValue valueFreeFunction;
+ PARCDictionary_ValueEquals valueEqualsFunction;
+ PARCTreeRedBlack *tree;
+};
+
+
+PARCDictionary *
+parcDictionary_Create(PARCDictionary_CompareKey keyCompareFunction,
+ PARCDictionary_KeyHashFunc keyHashFunction,
+ PARCDictionary_FreeKey keyFreeFunction,
+ PARCDictionary_ValueEquals valueEqualsFunction,
+ PARCDictionary_FreeValue valueFreeFunction)
+{
+ assertNotNull(keyCompareFunction, "KeyCompareFunction can't be null");
+ assertNotNull(keyHashFunction, "KeyHashFunction can't be null");
+ PARCDictionary *dictionary = parcMemory_Allocate(sizeof(PARCDictionary));
+ assertNotNull(dictionary, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCDictionary));
+ dictionary->keyCompareFunction = keyCompareFunction;
+ dictionary->keyHashFunction = keyHashFunction;
+ dictionary->keyFreeFunction = keyFreeFunction;
+ dictionary->valueFreeFunction = valueFreeFunction;
+ dictionary->valueEqualsFunction = valueEqualsFunction;
+ dictionary->tree = parcTreeRedBlack_Create(keyCompareFunction,
+ keyFreeFunction,
+ NULL,
+ valueEqualsFunction,
+ valueFreeFunction,
+ NULL);
+ return dictionary;
+}
+
+
+void
+parcDictionary_Destroy(PARCDictionary **dictionaryPointer)
+{
+ assertNotNull(dictionaryPointer, "Pointer to dictionary pointer can't be NULL");
+ assertNotNull(*dictionaryPointer, "Pointer to dictionary can't be NULL");
+ parcTreeRedBlack_Destroy(&((*dictionaryPointer)->tree));
+ parcMemory_Deallocate((void **) dictionaryPointer);
+ *dictionaryPointer = NULL;
+}
+
+void
+parcDictionary_SetValue(PARCDictionary *dictionary, void *key, void *value)
+{
+ assertNotNull(dictionary, "dictionary pointer can't be NULL");
+ assertNotNull(key, "Key pointer can't be NULL");
+ parcTreeRedBlack_Insert(dictionary->tree, key, value);
+}
+
+void *
+parcDictionary_GetValue(PARCDictionary *dictionary, const void *key)
+{
+ assertNotNull(dictionary, "dictionary pointer can't be NULL");
+ assertNotNull(key, "Key pointer can't be NULL");
+ return parcTreeRedBlack_Get(dictionary->tree, key);
+}
+
+void *
+parcDictionary_RemoveValue(PARCDictionary *dictionary, const void *key)
+{
+ assertNotNull(dictionary, "dictionary pointer can't be NULL");
+ assertNotNull(key, "Key pointer can't be NULL");
+ return parcTreeRedBlack_Remove(dictionary->tree, key);
+}
+
+void
+parcDictionary_RemoveAndDestroyValue(PARCDictionary *dictionary, const void *key)
+{
+ assertNotNull(dictionary, "dictionary pointer can't be NULL");
+ assertNotNull(key, "Key pointer can't be NULL");
+ parcTreeRedBlack_RemoveAndDestroy(dictionary->tree, key);
+}
+
+PARCArrayList *
+parcDictionary_Keys(const PARCDictionary *dictionary)
+{
+ assertNotNull(dictionary, "dictionary pointer can't be NULL");
+ return parcTreeRedBlack_Keys(dictionary->tree);
+}
+
+PARCArrayList *
+parcDictionary_Values(const PARCDictionary *dictionary)
+{
+ assertNotNull(dictionary, "dictionary pointer can't be NULL");
+ return parcTreeRedBlack_Values(dictionary->tree);
+}
+
+size_t
+parcDictionary_Size(const PARCDictionary *dictionary)
+{
+ assertNotNull(dictionary, "dictionary pointer can't be NULL");
+ return parcTreeRedBlack_Size(dictionary->tree);
+}
+
+int
+parcDictionary_Equals(const PARCDictionary *dictionary1, const PARCDictionary *dictionary2)
+{
+ assertNotNull(dictionary1, "dictionary pointer can't be NULL");
+ assertNotNull(dictionary2, "dictionary pointer can't be NULL");
+ return parcTreeRedBlack_Equals(dictionary1->tree, dictionary2->tree);
+}
diff --git a/libparc/parc/algol/parc_Dictionary.h b/libparc/parc/algol/parc_Dictionary.h
new file mode 100755
index 00000000..1ba98a65
--- /dev/null
+++ b/libparc/parc/algol/parc_Dictionary.h
@@ -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.
+ */
+
+/**
+ * @file parc_Dictionary.h
+ * @ingroup datastructures
+ * @brief
+ *
+ * The `PARCDictionary` is a dictionary of key value tuples.
+ *
+ */
+#ifndef libparc_parc_Dictionary_h
+#define libparc_parc_Dictionary_h
+
+#include <parc/algol/parc_ArrayList.h>
+
+#include <stdint.h>
+
+struct parc_dictionary;
+
+
+/**
+ * @typedef PARCDictionary
+ * @brief A PARCDictionary is a dictionary of key-values
+ */
+typedef struct parc_dictionary PARCDictionary;
+
+/**
+ * @typedef `PARCDictionary_CompareKey`
+ *
+ * @brief Compare two dictionary keys
+ *
+ * @param [in] key1 First dictionary key
+ * @param [in] key2 Second dictionary key
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef int (*PARCDictionary_CompareKey)(const void *key1,
+ const void *key2);
+/**
+ * @typedef `PARCDictionary_ValueEquals`
+ *
+ * @brief Compare two values
+ *
+ * @param [in] value1 A pointer to the First value
+ * @param [in] value2 A pointer to the Second value
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef bool (*PARCDictionary_ValueEquals)(const void *value1, const void *value2);
+
+
+/**
+ * @typedef `PARCDictionary_KeyHashFunc`
+ * @brief The key hash function must return a 32 bit hash of the key
+ * @param [in] key pointer to the key to be hashed
+ * @return uint32 hash
+ */
+
+typedef uint32_t (*PARCDictionary_KeyHashFunc)(const void *key);
+
+/**
+ * @typedef `PARCDictionary_FreeValue`
+ * @brief The free value must free a value.
+ * This will be called when a value for a key is changed.
+ * It will also be used when the Dictionary is destroyed on any
+ * values in the dictionary.
+ * @param [in,out] value The pointer to the pointer of the value to be freed.
+ */
+
+typedef void (*PARCDictionary_FreeValue)(void **value);
+
+/**
+ * @typedef `PARCDictionary_FreeKey`
+ * @brief The free key must free a key.
+ * This function will be called when the value for a key is removed from the
+ * dictionary. It's also called when the dictionary is destroyed.
+ * @param [in,out] key The pointer to the pointer to the key to be freed.
+ */
+
+typedef void (*PARCDictionary_FreeKey)(void **key);
+
+/**
+ * Create a Dictionary.
+ * You MUST set the function to compare keys and hash keys.
+ * You can give NULL as the free function of the key and the data,
+ * but why would you do that? :-)
+ *
+ * @param [in] keyCompareFunction The function that compares 2 keys (can't be NULL)
+ * @param [in] keyHashFunction The function to hash the keys to 32 bit values (can't be NULL)
+ * @param [in] keyFreeFunction The function to free the key (can be NULL)
+ * @param [in] valueEqualsFunction The function to know that values are equal. If NULL then values won't be compared on equality.
+ * @param [in] valueFreeFunction The function to free the values (can be NULL)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCDictionary *parcDictionary_Create(PARCDictionary_CompareKey keyCompareFunction,
+ PARCDictionary_KeyHashFunc keyHashFunction,
+ PARCDictionary_FreeKey keyFreeFunction,
+ PARCDictionary_ValueEquals valueEqualsFunction,
+ PARCDictionary_FreeValue valueFreeFunction);
+
+/**
+ * Destroy a Dictionary. If the Free functions were passed to the constructor and are not NULL
+ * they will be called for every element.
+ *
+ * @param [in,out] dictionaryPointer A pointer to the pointer to the instance of `PARCDictionary` to be destroyed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcDictionary_Destroy(PARCDictionary **dictionaryPointer);
+
+/**
+ * Set a value for a key.
+ * Both key and value will be referenced by the Dictionary. No memory copies will happen.
+ *
+ * If the key does not exist a new dictionary entry will be added pointing to the value.
+ *
+ * If the key does exists then the old value will be freed using the valueFree function (if not NULL).
+ * The old key will also be freed using the keyFree function (if not NULL).
+ *
+ * @param [in,out] dictionary A pointer to the specified `PARCDictionary`
+ * @param [in] key The key to insert in the dictionary. Can't be NULL.
+ * @param [in] value The value to associate with that key. Can't be NULL.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+void parcDictionary_SetValue(PARCDictionary *dictionary, void *key, void *value);
+
+/**
+ * Get a value from the dictionary associated with a specific key.
+ *
+ * @param [in] dictionary A PARCDictionary
+ * @param [in] key A pointer to the key. It must be valid as a parameter to the key compare function of the
+ * dictionary
+ * @return A pointer to the value.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcDictionary_GetValue(PARCDictionary *dictionary, const void *key);
+
+/**
+ * Remove a value from the dictionary. This will return the value referenced by the key. It will remove it
+ * in the process. The key will be freed with the keyFree function (if not NULL)
+ *
+ * @param [in,out] dictionary A `PARCDictionary`
+ * @param [in] key A pointer to the key. It must be valid as a parameter to the key compare function of the dictionary.
+ * @return A pointer to the value.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcDictionary_RemoveValue(PARCDictionary *dictionary, const void *key);
+
+/**
+ * Delete an entry from the dictionary.
+ * This will remove an entry from the dictionary and free both the key and the value using the functions
+ * provided at the creation of the dictionary.
+ *
+ * @param [in,out] dictionary A pointer to an instance of `PARCDictionary`
+ * @param [in] key A pointer to the key. It must be valid as a parameter to the key compare function of the dictionary.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcDictionary_RemoveAndDestroyValue(PARCDictionary *dictionary, const void *key);
+
+/**
+ * Get a list of the keys from this dictionary.
+ *
+ * @param [in] dictionary A `PARCDictionary`
+ * @return A pointer to a {@link PARCArrayList} of (pointers to) keys. All of these keys will be valid keys in the dictionary.
+ * The caller will own the list of keys and should destroy it when done. The caller will not own
+ * the key themselves. (Destroying the `PARCArrayList` should be enough).
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCArrayList *parcDictionary_Keys(const PARCDictionary *dictionary);
+
+/**
+ * Get a list of the values from this dictionary.
+ * The caller will own the list of values and should destroy it when done. The caller will not own
+ * the values themselves. Destroying the {@link PARCArrayList} should be enough.
+ *
+ * Note that if the Dictionary is destroyed the value pointers might no longer point to valid values.
+ *
+ * @param [in] dictionary A pointer to an instance of `PARCDictionary`
+ * @return A pointer to a `PARCArrayList` of (pointers to) values.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCArrayList *parcDictionary_Values(const PARCDictionary *dictionary);
+
+/**
+ * Return the number of entries in the dictionary.
+ *
+ * @param [in] dictionary A pointer to an instance of `PARCDictionary`
+ * @return The number of keys in the dictionary.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcDictionary_Size(const PARCDictionary *dictionary);
+
+
+/**
+ * Determine if two `PARCDictionary` instances are equal.
+ *
+ * Two `PARCDictionary` instances are equal if, and only if, the trees are equal
+ *
+ * The following equivalence relations on non-null `PARCDictionary` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCDictionary_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcDictionary_Equals(x, y)` must return true if and only if
+ * `parcDictionary_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcDictionary_Equals(x, y)` returns true and
+ * `parcDictionary_Equals(y, z)` returns true,
+ * then `parcDictionary_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcDictionary_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcDictionary_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] dictionary1 A pointer to a `PARCDictionary` instance.
+ * @param [in] dictionary2 A pointer to a `PARCDictionary` instance.
+ * @return true if the two `PARCDictionary` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDictionary *a = parcDictionary_Create();
+ * PARCDictionary *b = parcDictionary_Create();
+ *
+ * if (parcDictionary_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+int parcDictionary_Equals(const PARCDictionary *dictionary1, const PARCDictionary *dictionary2);
+#endif // libparc_parc_Dictionary_h
diff --git a/libparc/parc/algol/parc_DisplayIndented.c b/libparc/parc/algol/parc_DisplayIndented.c
new file mode 100755
index 00000000..5e043c15
--- /dev/null
+++ b/libparc/parc/algol/parc_DisplayIndented.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+
+static char *_spaces = " ";
+
+static size_t _indentationFactor = 2;
+
+static size_t
+_indent(int indentation)
+{
+ size_t result = 0;
+
+ if (indentation > 0) {
+ result = write(1, _spaces, indentation * _indentationFactor);
+ assertTrue(result == (indentation * _indentationFactor),
+ "Write(2) failed to write %zd bytes.", indentation * _indentationFactor);
+ }
+ return result;
+}
+
+static void
+_parcDisplayIndented_Print(int indentation, char *string)
+{
+ char *start = string;
+ char *end = strchr(start, '\n');
+
+ while (start != NULL) {
+ _indent(indentation);
+ if (end != NULL) {
+ ssize_t nwritten = write(1, start, end - start + 1);
+ assertTrue(nwritten >= 0, "Error calling write");
+ start = end + 1;
+ } else {
+ ssize_t nwritten = write(1, start, strlen(start));
+ assertTrue(nwritten >= 0, "Error calling write");
+ break;
+ }
+ end = strchr(start, '\n');
+ }
+}
+
+void
+parcDisplayIndented_PrintLine(int indentation, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+
+ char *cString;
+ int length = vasprintf(&cString, format, ap);
+ assertTrue(length >= 0, "Error in vasprintf");
+
+ va_end(ap);
+
+ _parcDisplayIndented_Print(indentation, cString);
+
+ ssize_t nwritten = write(1, "\n", 1);
+ assertTrue(nwritten >= 0, "Error calling write");
+
+ free(cString);
+}
+
+void
+parcDisplayIndented_PrintMemory(int indentation, size_t length, const char memory[length])
+{
+ int bytesPerLine = 16;
+
+ char accumulator[bytesPerLine + 1];
+ memset(accumulator, ' ', bytesPerLine);
+ accumulator[bytesPerLine] = 0;
+
+ char *cString;
+ for (size_t offset = 0; offset < length; /**/) {
+ int nwritten = asprintf(&cString, "%p=[", &memory[offset]);
+ assertTrue(nwritten >= 0, "Error calling asprintf");
+ _parcDisplayIndented_Print(indentation, cString);
+ free(cString);
+
+ size_t bytesInLine = (length - offset) < bytesPerLine ? (length - offset) : bytesPerLine;
+ for (size_t i = 0; i < bytesInLine; i++) {
+ char c = memory[offset + i];
+ printf("0x%02x, ", c & 0xFF);
+ accumulator[i] = isprint(c) ? c : '.';
+ }
+ offset += bytesInLine;
+ }
+ printf(" %s]\n", accumulator);
+}
diff --git a/libparc/parc/algol/parc_DisplayIndented.h b/libparc/parc/algol/parc_DisplayIndented.h
new file mode 100644
index 00000000..753f942d
--- /dev/null
+++ b/libparc/parc/algol/parc_DisplayIndented.h
@@ -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.
+ */
+
+/**
+ * @file parc_DisplayIndented.h
+ * @ingroup developer
+ * @brief Support for displaying information on the console.
+ *
+ *
+ */
+#ifndef libparc_parc_DisplayIndented_h
+#define libparc_parc_DisplayIndented_h
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+/**
+ * Print an indented, formatted string on standard output.
+ *
+ * The line is automatically terminated with a new line.
+ *
+ * @param [in] indentation The indentation level of the output.
+ * @param [in] format The format string.
+ * @param [in] ... A variable number of arguments.
+ *
+ * Example:
+ * @code
+ * {
+ * parcDisplayIndented_PrintLine(2, "This is printed on standard output, at indentation level 2");
+ * }
+ * @endcode
+ */
+void parcDisplayIndented_PrintLine(int indentation, const char *format, ...);
+
+/**
+ * Print memory.
+ *
+ * @param [in] indentation The indentation level of the output.
+ * @param [in] length The length of the array.
+ * @param [in] memory The memory array.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcDisplayIndented_PrintMemory(int indentation, size_t length, const char *memory);
+#endif // libparc_parc_DisplayIndented_h
diff --git a/libparc/parc/algol/parc_ElasticString.h b/libparc/parc/algol/parc_ElasticString.h
new file mode 100755
index 00000000..c6e39eb1
--- /dev/null
+++ b/libparc/parc/algol/parc_ElasticString.h
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_ElasticString.h
+ * @ingroup memory
+ * @brief An elastic C string.
+ *
+ * An elastic string is a dynamic array of characters which are readily expressed as a
+ * nul-terminated C string.
+ *
+ */
+#ifndef libparc_parc_ElasticString_h
+#define libparc_parc_ElasticString_h
+
+#include <stdarg.h>
+
+#include <parc/algol/parc_Buffer.h>
+
+struct parc_elastic_string;
+typedef struct parc_elastic_string PARCElasticString;
+
+/**
+ * Perform validation on a pointer to a `PARCElasticString`.
+ *
+ * If invalid, this function will abort the running process.
+ *
+ * @param * string A pointer to a `PARCElasticString` to validate.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ *
+ * parcElasticString_AssertValid(string);
+ * }
+ * @endcode
+ */
+void parcElasticString_AssertValid(const PARCElasticString *string);
+
+/**
+ * Create an empty `PARCElasticString` instance.
+ *
+ * The instance will be empty upon initialization (i.e., `parcElasticString_ToString()` will
+ * return an empty string), but characters and strings may be inserted/appended to
+ * the instance to produce usable content,
+ *
+ * @return A pointer to an allocated `PARCElasticString` that must be freed with `parcElasticString_Release()`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ *
+ * // use the string as necessary
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ */
+PARCElasticString *parcElasticString_Create(void);
+
+/**
+ * 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 * string A pointer to a pointer to the instance to release.
+ *
+ * @return The number of remaining references to the object.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCElasticString *buffer = parcElasticString_Create();
+ *
+ * parcElasticString_Release(&pathName);
+ * }
+ * @endcode
+ */
+void parcElasticString_Release(PARCElasticString **string);
+
+/**
+ * Retrieve the number of remaining bytes between the current position
+ * in the string and its (flexible) limit.
+ *
+ * @param * string A pointer to an `PARCElasticString` instance.
+ *
+ * @return The non-negative number of characters remaining between the position and limit.
+ *
+ * Example:
+ * @code
+ * {
+ * char *inputString = "Hello World";
+ * size_t inputLength = strlen(input);
+ * PARElasticString *string = parcElasticString_Create();
+ * parcElasticString_PutString(string, inputString);
+ * parcElasticString_Flip(string);
+ * size_t numRemaining = parcElasticString_Remaining(string);
+ *
+ * // numRemaining == inputLength
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ */
+size_t parcElasticString_Remaining(const PARCElasticString *string);
+
+/**
+ * Set the limit to the current position, then the position to zero.
+ * If the mark is defined, it is invalidated,
+ * and any subsequent operation that requires the mark will abort until the mark
+ * is set again via `parcElasticString_Mark`.
+ *
+ * @param * string A pointer to an `PARCElasticString` instance.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * char *inputString = "Hello World";
+ * size_t inputLength = strlen(input);
+ * PARElasticString *string = parcElasticString_Create();
+ * parcElasticString_PutString(string, inputString);
+ * parcElasticString_Flip(string);
+ * size_t numRemaining = parcElasticString_Remaining(string);
+ *
+ * // numRemaining == inputLength
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ */
+PARCElasticString *parcElasticString_Flip(PARCElasticString *string);
+
+/**
+ * Return the given `PARCElasticString`'s position.
+ *
+ * A buffer's position is the index of the next element to be read or written.
+ * A buffer's position is never negative and is never greater than its limit.
+ *
+ * @param * string A pointer to a `PARCElasticString` instance.
+ *
+ * @return The given `PARCElasticString`'s position.
+ *
+ * Example:
+ * @code
+ * {
+ * size_t currentPosition = parcBuffer_Position(buffer);
+ * }
+ * @endcode
+ *
+ * @see parcElasticString_SetPosition
+ */
+size_t parcElasticString_Position(const PARCElasticString *string);
+
+/**
+ * Set the position in the given `PARCElasticString`.
+ *
+ * If the mark is defined and larger than the new position then it is invalidated.
+ *
+ * @param * string A pointer to a `PARCElasticString` instance.
+ * @param * newPosition The new position for the `PARCElasticString`.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ * parcElasticString_PutString(string, "Hello World");
+ *
+ * parcElasticString_SetPosition(string, 0);
+ *
+ * // position is now at 0, instead of at the end of "Hello World"
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ *
+ * @see parcElasticString_Position
+ */
+PARCElasticString *parcElasticString_SetPosition(PARCElasticString *string, size_t newPosition);
+
+/**
+ * Append an array with the specified number of bytes to the end of this `PARCElasticString` instance.
+ *
+ * The position of the string is advanced by the length of the array.
+ *
+ * @param * string A pointer to a `PARCElasticString` instance.
+ * @param * array A pointer to the array containing the bytes to append.
+ * @param * length The length of the input array.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ *
+ * uint8_t * appendArray = { 0x00, 0x01, 0x02, 0x03, 0x04 };
+ * parcElasticString_PutArray(string, appendArray, 5);
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ *
+ * @see parcElasticString_PutString
+ */
+PARCElasticString *parcElasticString_PutArray(PARCElasticString *string, const char *array, size_t length);
+
+/**
+ * Append a C-string to the end of this `PARCElasticString` instance.
+ *
+ * The position of the string is advanced by the length of the string.
+ *
+ * @param * string A pointer to a `PARCElasticString` instance.
+ * @param * cString A pointer to a nul-terminated C string to append to this `PARCElasticString`.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ *
+ * parcElasticString_PutString(string, "Hello World");
+ * printf("String = %s\n", parcElasticString_ToString(string));
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ *
+ * @see parcElasticString_PutArray
+ */
+PARCElasticString *parcElasticString_PutString(PARCElasticString *string, const char *cString);
+
+/**
+ * Append the contents of a `PARCBuffer` instance to the end of the `PARCElasticString` instance.
+ *
+ * The position of the string is advanced by the length of the buffer.
+ *
+ * @param * string A pointer to a `PARCElasticString` instance.
+ * @param * buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ *
+ * uint8_t * array = { 'H', 'e', 'l', 'l', 'o' };
+ * PARCBuffer *endBuffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutArray(endBuffer, 5, array);
+ * parcElasticString_PutBuffer(string, endBuffer);
+ *
+ * printf("String = %s\n", parcElasticString_ToString(string));
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ *
+ * @see parcElasticString_PutString
+ */
+PARCElasticString *parcElasticString_PutBuffer(PARCElasticString *string, PARCBuffer *buffer);
+
+/**
+ * Append a single character (byte) to the end of this string.
+ *
+ * The position of the string is advanced by one (1).
+ *
+ * @param * string A pointer to `PARCElasticString`
+ * @param * character A `char` value to append.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ *
+ * parcElasticString_PutChar(string, 'H');
+ * parcElasticString_PutChar(string, 'e');
+ * parcElasticString_PutChar(string, 'l');
+ * parcElasticString_PutChar(string, 'l');
+ * parcElasticString_PutChar(string, 'o');
+ *
+ * printf("String = %s\n", parcElasticString_ToString(string));
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ *
+ * @see parcElasticString_PutString
+ */
+PARCElasticString *parcElasticString_PutChar(PARCElasticString *string, const char character);
+
+/**
+ * Put a variable number of characters into the `PARCElasticString`.
+ *
+ * @param * string The `PARCElasticString` to receive the characters.
+ * @param * count The number of characters to insert into the `PARCElasticString`
+ * @param * ... The characters to insert into the `PARCElasticString`.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ *
+ * parcElasticString_PutChar(string, 5, 'H', 'e', 'l', 'l', 'o');
+ *
+ * printf("String = %s\n", parcElasticString_ToString(string));
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ *
+ * @see parcElasticString_PutString
+ */
+PARCElasticString *parcElasticString_PutChars(PARCElasticString *string, unsigned int count, ...);
+
+/**
+ * Append an arbitrary number of C-style strings to the given `PARCElasticString` instance.
+ *
+ * @param * string A pointer to `PARCElasticString`
+ * @param * ... The nul-terminated, C-style strings to append to the given `PARCElasticString`.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *baseString = parcElasticString_Create();
+ * parcElasticString_PutString(baseString, "Hello");
+ * uint8_t * string1 = {' ', '\0'};
+ * uint8_t * string2 = {'W', 'o', 'r', 'l', 'd', '\0'};
+ *
+ * parcElasticString_PutStrings(baseString, string1, string2);
+ *
+ * printf("String = %s\n", parcElasticString_ToString(baseString));
+ *
+ * parcElasticString_Release(&baseString);
+ * }
+ * @endcode
+ */
+PARCElasticString *parcElasticString_PutStrings(PARCElasticString *string, ...);
+
+/**
+ * Append a formatted nul-terminated, C-style string string to the given `PARCElasticString` instance.
+ *
+ * @param * string A pointer to `PARCElasticString`.
+ * @param * format The format string
+ * @param * ... Remaining parameters used to format the string.
+ *
+ * @return The same pointer as the `string` parameter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ *
+ * parcElasticString_Format(string, "Hello %s\n", "World");
+ *
+ * printf("String = %s\n", parcElasticString_ToString(string));
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ */
+PARCElasticString *parcElasticString_Format(PARCElasticString *string, const char *format, ...) \
+ __attribute__((format(printf, 2, 3)));
+
+/**
+ * Retrieve a handle to the `PARCBuffer` instance. The reference count is not increased.
+ *
+ * @param * string A pointer to `PARCElasticString`.
+ *
+ * @return The `PARCBuffer` instance used to encapsulate the `PARCElasticString` contents.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ * parcElasticString_PutString(string, "Hello World");
+ *
+ * PARCBuffer *buffer = parcElasticString_ToBuffer(string);
+ * printf("String in hex = %s\n", parcBuffer_ToHexString(buffer));
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcElasticString_ToBuffer(const PARCElasticString *string);
+
+/**
+ * Produce a C string representation of the given `PARCElasticString`.
+ *
+ * Produce an allocated, nul-terminated string representation of the given `PARCElasticString`.
+ * The result must be freed by the caller via the `parcMemory_Deallocate()` function.
+ *
+ * @param * string A pointer to `PARCElasticString`.
+ *
+ * @return A pointer to an allocated array containing a nul-terminated string the must be freed via `parcMemory_Deallocate()`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARElasticString *string = parcElasticString_Create();
+ * parcElasticString_PutString(string, "Hello World");
+ *
+ * printf("String = %s\n", parcElasticString_ToString(string));
+ *
+ * parcElasticString_Release(&string);
+ * }
+ * @endcode
+ */
+char *parcElasticString_ToString(const PARCElasticString *string);
+#endif // libparc_parc_ElasticString_h
diff --git a/libparc/parc/algol/parc_Environment.c b/libparc/parc/algol/parc_Environment.c
new file mode 100644
index 00000000..2955a139
--- /dev/null
+++ b/libparc/parc/algol/parc_Environment.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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_Environment.h>
+#include <parc/algol/parc_File.h>
+
+const char *
+parcEnvironment_GetHomeDirectory(void)
+{
+ char *result = getenv("HOME");
+ return result;
+}
+
+PARCFile *
+parcEnvironment_HomeDirectory(void)
+{
+ char *path;
+
+ if ((path = getenv("HOME")) == NULL) {
+ path = getpwuid(getuid())->pw_dir;
+ }
+
+ return parcFile_Create(path);
+}
diff --git a/libparc/parc/algol/parc_Environment.h b/libparc/parc/algol/parc_Environment.h
new file mode 100755
index 00000000..04610176
--- /dev/null
+++ b/libparc/parc/algol/parc_Environment.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 parc_Environment.h
+ * @ingroup inputoutput
+ * @brief Functions to access and manipulate the runtime environment.
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#ifndef libparc_parc_Environment_h
+#define libparc_parc_Environment_h
+
+/**
+ *
+ * Get the current home directory for the running process.
+ *
+ * @return A C string containing the name of the home directory.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *parcEnvironment_GetHomeDirectory(void);
+#endif // libparc_parc_Environment_h
diff --git a/libparc/parc/algol/parc_Event.c b/libparc/parc/algol/parc_Event.c
new file mode 100755
index 00000000..0a8391aa
--- /dev/null
+++ b/libparc/parc/algol/parc_Event.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 <LongBow/runtime.h>
+
+#include "internal_parc_Event.h"
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_Event.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/logging/parc_Log.h>
+#include <parc/logging/parc_LogReporterFile.h>
+
+static int _parc_event_debug_enabled = 0;
+
+#define parcEvent_LogDebug(parcEvent, ...) \
+ if (_parc_event_debug_enabled) \
+ parcLog_Debug(parcEventScheduler_GetLogger(parcEvent->parcEventScheduler), __VA_ARGS__)
+
+/**
+ * Current implementation based on top of libevent2
+ */
+#include <event2/event.h>
+
+/**
+ * @typedef PARCEvent
+ * @brief A structure containing private event state data variables
+ */
+struct PARCEvent {
+ /**
+ * The event instance.
+ */
+ struct event *event;
+
+ // Event scheduler we have been queued with
+ PARCEventScheduler *parcEventScheduler;
+
+ // Interpose on callback
+ PARCEvent_Callback *callback;
+ void *callbackUserData;
+
+ void *user_data;
+};
+
+static void
+_parc_event_callback(evutil_socket_t fd, short flags, void *context)
+{
+ PARCEvent *parcEvent = (PARCEvent *) context;
+ parcEvent_LogDebug(parcEvent, "_parc_event_callback(fd=%x,flags=%x,parcEvent=%p)\n", fd, flags, parcEvent);
+
+ parcEvent->callback((int) fd, internal_libevent_type_to_PARCEventType(flags), parcEvent->callbackUserData);
+}
+
+PARCEvent *
+parcEvent_Create(PARCEventScheduler *parcEventScheduler, int fd, PARCEventType flags, PARCEvent_Callback *callback, void *callbackArgs)
+{
+ PARCEvent *parcEvent = parcMemory_Allocate(sizeof(PARCEvent));
+ assertNotNull(parcEvent, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCEvent));
+
+ parcEvent->parcEventScheduler = parcEventScheduler;
+ parcEvent->callback = callback;
+ parcEvent->callbackUserData = callbackArgs;
+
+ parcEvent->event = event_new(parcEventScheduler_GetEvBase(parcEventScheduler), fd,
+ internal_PARCEventType_to_libevent_type(flags), _parc_event_callback, parcEvent);
+ assertNotNull(parcEvent->event, "Could not create a new event!");
+
+ parcEvent_LogDebug(parcEvent,
+ "parcEvent_Create(base=%p,fd=%x,events=%x,cb=%p,args=%p)\n",
+ parcEventScheduler_GetEvBase(parcEventScheduler), fd, flags, callback, parcEvent);
+
+ return parcEvent;
+}
+
+int
+parcEvent_Start(PARCEvent *parcEvent)
+{
+ parcEvent_LogDebug(parcEvent, "parcEvent_Start(%p)\n", parcEvent);
+ assertNotNull(parcEvent, "parcEvent_Start must be passed a valid event!");
+
+ int result = event_add(parcEvent->event, NULL);
+ return result;
+}
+
+int
+parcEvent_Stop(PARCEvent *parcEvent)
+{
+ parcEvent_LogDebug(parcEvent, "parcEvent_Stop(%p)\n", parcEvent);
+ assertNotNull(parcEvent, "parcEvent_Stop must be passed a valid event!");
+
+ int result = event_del(parcEvent->event);
+ return result;
+}
+
+int
+parcEvent_Poll(PARCEvent *parcEvent, PARCEventType event)
+{
+ parcEvent_LogDebug(parcEvent, "parcEvent_Stop(%p)\n", parcEvent);
+ assertNotNull(parcEvent, "parcEvent_Stop must be passed a valid event!");
+
+ int result = event_pending(parcEvent->event, event, NULL);
+ return result;
+}
+
+void
+parcEvent_Destroy(PARCEvent **parcEvent)
+{
+ parcEvent_LogDebug((*parcEvent), "parcEvent_Destroy(%p)\n", *parcEvent);
+ assertNotNull(*parcEvent, "parcEvent_Destroy must be passed a valid parcEvent!");
+ assertNotNull((*parcEvent)->event, "parcEvent_Destroy passed a null event!");
+
+ event_free((*parcEvent)->event);
+ parcMemory_Deallocate((void **) parcEvent);
+}
+
+int
+parcEvent_SetPriority(PARCEvent *parcEvent, PARCEventPriority priority)
+{
+ parcEvent_LogDebug(parcEvent, "parcEvent_Stop(%p)\n", parcEvent);
+
+ return event_priority_set(parcEvent->event, internal_PARCEventPriority_to_libevent_priority(priority));
+}
+
+void
+parcEvent_EnableDebug(void)
+{
+ _parc_event_debug_enabled = 1;
+}
+
+void
+parcEvent_DisableDebug(void)
+{
+ _parc_event_debug_enabled = 0;
+}
diff --git a/libparc/parc/algol/parc_Event.h b/libparc/parc/algol/parc_Event.h
new file mode 100644
index 00000000..3f2fde98
--- /dev/null
+++ b/libparc/parc/algol/parc_Event.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 parc_Event.h
+ * @ingroup events
+ * @brief Event management
+ *
+ * Provides a facade implementing many regularly available event functions.
+ * This is an interface that software implementors may use to substitute
+ * different kinds of underlying implementations of these event management functions.
+ * Notable examples are libevent and libev.
+ *
+ */
+#ifndef libparc_parc_Event_h
+#define libparc_parc_Event_h
+
+/**
+ * Current implementation based on top of libevent2
+ */
+
+#include <parc/algol/parc_EventScheduler.h>
+
+/**
+ * @typedef PARCEventType
+ * @brief An enumeration of event types, with an additional persist flag
+ */
+typedef enum {
+ PARCEventType_None = 0x00,
+ PARCEventType_Timeout = 0x01,
+ PARCEventType_Read = 0x02,
+ PARCEventType_Write = 0x04,
+ PARCEventType_Signal = 0x08,
+ PARCEventType_Persist = 0x10,
+ PARCEventType_EdgeTriggered = 0x20
+} PARCEventType;
+
+/**
+ * @typedef PARCEventPriority
+ * @brief Priority flags for queue scheduling, these currently match the RTA_*_PRIORITY
+ * this will eventually be replaced.
+ */
+typedef enum {
+ PARCEventPriority_Maximum = 0,
+ PARCEventPriority_Normal = 1,
+ PARCEventPriority_Minimum = 2,
+ PARCEventPriority_NumberOfPriorities = 3
+} PARCEventPriority;
+
+/**
+ * @typedef PARCEvent_Callback
+ * @brief Event callback definition
+ */
+typedef void (PARCEvent_Callback)(int fileDescriptor, PARCEventType type, void *user_data);
+
+/**
+ * @typedef PARCEvent
+ * @brief A structure containing private libevent state data variables
+ */
+typedef struct PARCEvent PARCEvent;
+
+/**
+ * Create a new PARCEvent instance.
+ *
+ * A new PARCEvent instance is returned.
+ *
+ * @param [in] parcEventScheduler base instance
+ * @param [in] fileDescriptor file descriptor to monitor
+ * @param [in] events to catch
+ * @param [in] callback function
+ * @param [in] callbackArgs function private arguments
+ * @returns A pointer to the a PARCEvent instance.
+ *
+ * Example:
+ * @code
+ * static void
+ * _read_callback(int fileDescriptor, PARCEventType type, void *args)
+ * {
+ * }
+ *
+ * {
+ * PARCEventScheduler *eventScheduler = parcEventScheduer_Create();
+ * PARCEvent *event = parcEvent_Create(eventScheduler, fileDescriptor, PARCEvent_ReadEvent, _read_callback, _read_callback_args);
+ * }
+ * @endcode
+ *
+ */
+PARCEvent *parcEvent_Create(PARCEventScheduler *parcEventScheduler, int fileDescriptor, PARCEventType events, PARCEvent_Callback *callback, void *callbackArgs);
+
+/**
+ * Start an event instance.
+ *
+ * @param [in] parcEvent instance to start
+ * @returns -1 on error, 0 on success if nothing changed in the parcEvent backend, and 1 on success if something did.
+ *
+ * Example:
+ * @code
+ * startEvent(PARCEvent *parcEvent)
+ * {
+ * return parcEvent_Start(parcEvent);
+ * }
+ * @endcode
+ *
+ */
+int parcEvent_Start(PARCEvent *parcEvent);
+
+/**
+ * Stop a parcEvent instance.
+ *
+ * @param [in] parcEvent instance to stop
+ * @returns -1 on error, 0 on success.
+ *
+ * Example:
+ * @code
+ * removeEvent(PARCEvent *parcEvent)
+ * {
+ * return parcEvent_Stop(parcEvent);
+ * }
+ * @endcode
+ *
+ */
+int parcEvent_Stop(PARCEvent *parcEvent);
+
+/**
+ * Poll if an event is available to process
+ *
+ * @param [in] parcEvent instance to stop
+ * @param [in] event type to poll for
+ * @returns -1 on error, 0 on success.
+ *
+ * Example:
+ * @code
+ * pollReadEvent(PARCEvent *parcEvent)
+ * {
+ * return parcEvent_Poll(parcEvent, PARCEvent_ReadEvent);
+ * }
+ * @endcode
+ *
+ */
+int parcEvent_Poll(PARCEvent *parcEvent, PARCEventType event);
+
+/**
+ * Destroy a parcEvent instance.
+ *
+ * @param [in] parcEvent address of instance to destroy.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEvent_Destroy(&parcEvent);
+ * }
+ * @endcode
+ *
+ */
+void parcEvent_Destroy(PARCEvent **parcEvent);
+
+/**
+ * Set a parcEvent instances priority.
+ *
+ * @param [in] parcEvent instance to modify
+ * @param [in] priority to set to
+ * @returns -1 on error, 0 on success.
+ *
+ * Example:
+ * @code
+ * {
+ * return parcEvent_SetPriority(parcEvent, priority);
+ * }
+ * @endcode
+ *
+ */
+int parcEvent_SetPriority(PARCEvent *parcEvent, PARCEventPriority priority);
+
+/**
+ * Turn on debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEvent_EnableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEvent_EnableDebug(void);
+
+/**
+ * Turn off debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEvent_DisableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEvent_DisableDebug(void);
+#endif // libparc_parc_Event_h
diff --git a/libparc/parc/algol/parc_EventBuffer.c b/libparc/parc/algol/parc_EventBuffer.c
new file mode 100644
index 00000000..49ba3354
--- /dev/null
+++ b/libparc/parc/algol/parc_EventBuffer.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "internal_parc_Event.h"
+#include <parc/algol/parc_Event.h>
+#include <parc/algol/parc_EventBuffer.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/logging/parc_Log.h>
+#include <parc/logging/parc_LogReporterFile.h>
+
+static PARCLog *parcEventBufferDebugLog = NULL;
+
+#define parcEventBuffer_LogDebug(parcEvent, ...) \
+ if (parcEventBufferDebugLog) \
+ parcLog_Debug(parcEventBufferDebugLog, __VA_ARGS__)
+
+/**
+ * Current implementation based on top of libevent2
+ */
+
+#include <event2/buffer.h>
+
+/**
+ * @typedef PARCEventBuffer
+ * @brief A structure containing private libevent state data variables
+ *
+ * The evbuffer either points to an evbuffer owned by the bufferevent, or an
+ * allocated evbuffer (allocated_evbuffer) that is our responsibility to destroy.
+ */
+struct PARCEventBuffer {
+ struct evbuffer *evbuffer;
+ struct evbuffer *allocated_evbuffer;
+};
+
+PARCEventBuffer *
+parcEventBuffer_Create(void)
+{
+ internal_parc_initializeLibevent();
+ struct evbuffer *new_evbuffer = evbuffer_new();
+ assertNotNull(new_evbuffer, "libevent returned a null evbuffer.\n");
+
+ PARCEventBuffer *parcEventBuffer = parcMemory_AllocateAndClear(sizeof(PARCEventBuffer));
+ assertNotNull(parcEventBuffer, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCEventBuffer));
+ parcEventBuffer->allocated_evbuffer = new_evbuffer;
+ parcEventBuffer->evbuffer = parcEventBuffer->allocated_evbuffer;
+
+ parcEventBuffer_LogDebug(parcEventBuffer, "parcEventBuffer_Create() = %p\n", parcEventBuffer);
+
+ return parcEventBuffer;
+}
+
+void
+parcEventBuffer_Destroy(PARCEventBuffer **parcEventBuffer)
+{
+ parcEventBuffer_LogDebug((*parcEventBuffer), "parcEventBuffer_Destroy(parcEventBuffer=%p)\n", *parcEventBuffer);
+ assertNotNull(parcEventBuffer, "parcEventBuffer_Destroy was passed a null parcEventBuffer pointer\n");
+ assertNotNull(*parcEventBuffer, "parcEventBuffer_Destroy was passed a null parcEventBuffer\n");
+
+ // Destroy allocated eveventBuffer if it was allocated by us, otherwise it's owned by bufferevent
+ if ((*parcEventBuffer)->allocated_evbuffer) {
+ parcEventBuffer_LogDebug((*parcEventBuffer), "parcEventBuffer_Destroy(parcEventBuffer=%p) freeing evbuffer %p\n", *parcEventBuffer, (*parcEventBuffer)->allocated_evbuffer);
+ evbuffer_free((*parcEventBuffer)->allocated_evbuffer);
+ }
+ parcMemory_Deallocate((void **) parcEventBuffer);
+ parcEventBuffer_LogDebug((*parcEventBuffer), "parcEventBuffer_Destroy() buffer already deallocated\n");
+}
+
+bool
+parcEventBuffer_IsValid(const PARCEventBuffer *eventBuffer)
+{
+ bool result = false;
+
+ if (eventBuffer != NULL) {
+ if (eventBuffer->evbuffer) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+void
+parcEventBuffer_AssertValid(const PARCEventBuffer *eventBuffer)
+{
+ assertTrue(parcEventBuffer_IsValid(eventBuffer),
+ "PARCEventBuffer@%p is not valid.", (void *) eventBuffer);
+}
+
+size_t
+parcEventBuffer_GetLength(PARCEventBuffer *parcEventBuffer)
+{
+ parcEventBuffer_LogDebug(parcEventBuffer, "parcEventBuffer_GetLength(parcEventBuffer=%p)\n", parcEventBuffer);
+// parcEventBuffer_OptionalAssertValid(parcEventBuffer);
+ assertNotNull(parcEventBuffer, "parcEventBuffer_GetLength was passed a null parcEventBuffer\n");
+
+ if (parcEventBuffer->evbuffer) {
+ return evbuffer_get_length(parcEventBuffer->evbuffer);
+ } else {
+ return 0;
+ }
+}
+
+uint8_t *
+parcEventBuffer_Pullup(PARCEventBuffer *parcEventBuffer, ssize_t size)
+{
+ parcEventBuffer_LogDebug(parcEventBuffer, "parcEventBuffer_Pullup(parcEventBuffer=%p,size=%zx)\n", parcEventBuffer, size);
+
+ parcEventBuffer_OptionalAssertValid(parcEventBuffer);
+// assertNotNull(parcEventBuffer, "parcEventBuffer_Pullup was passed a null parcEventBuffer\n");
+// assertNotNull(parcEventBuffer->evbuffer, "parcEventBuffer_Pullup was passed a null libevent evbuffer\n");
+
+ return evbuffer_pullup(parcEventBuffer->evbuffer, (ev_ssize_t) size);
+}
+
+int
+parcEventBuffer_ReadIntoBuffer(PARCEventBuffer *source, PARCEventBuffer *destination, size_t length)
+{
+ parcEventBuffer_OptionalAssertValid(source);
+ parcEventBuffer_OptionalAssertValid(destination);
+// assertNotNull(source, "parcEventBuffer_ReadIntoBuffer was passed a null source buffer\n");
+// assertNotNull(source->evbuffer, "parcEventBuffer_ReadIntoBuffer was passed a null source evbuffer\n");
+// assertNotNull(destination, "parcEventBuffer_ReadIntoBuffer was passed a null destination buffer\n");
+// assertNotNull(destination->evbuffer, "parcEventBuffer_ReadIntoBuffer was passed a null destination evbuffer\n");
+
+ return evbuffer_remove_buffer(source->evbuffer, destination->evbuffer, length);
+}
+
+int
+parcEventBuffer_Read(PARCEventBuffer *readBuffer, void *data, size_t length)
+{
+ parcEventBuffer_OptionalAssertValid(readBuffer);
+// assertNotNull(readBuffer, "parcEventBuffer_Read was passed a null buffer\n");
+// assertNotNull(readBuffer->evbuffer, "parcEventBuffer_Read was passed a null libevent evbuffer\n");
+
+ if (data == NULL) {
+ return evbuffer_drain(readBuffer->evbuffer, length);
+ } else {
+ return evbuffer_remove(readBuffer->evbuffer, data, length);
+ }
+}
+
+int
+parcEventBuffer_copyOut(PARCEventBuffer *readBuffer, void *data_out, size_t length)
+{
+ assertNotNull(data_out, "parcEventBuffer_Copy was passed a null data_out buffer\n");
+ parcEventBuffer_OptionalAssertValid(readBuffer);
+ return evbuffer_copyout(readBuffer->evbuffer, data_out, length);
+}
+
+int
+parcEventBuffer_WriteToFileDescriptor(PARCEventBuffer *writeBuffer, int fd, ssize_t length)
+{
+ parcEventBuffer_OptionalAssertValid(writeBuffer);
+
+// assertNotNull(writeBuffer, "parcEventBuffer_WriteToFileDescriptor was passed a null buffer\n");
+// assertNotNull(writeBuffer->evbuffer, "parcEventBuffer_WriteToFileDescriptor was passed a null libevent evbuffer\n");
+
+ return evbuffer_write_atmost(writeBuffer->evbuffer, fd, length);
+}
+
+int
+parcEventBuffer_ReadFromFileDescriptor(PARCEventBuffer *readBuffer, int fd, size_t length)
+{
+ parcEventBuffer_OptionalAssertValid(readBuffer);
+// assertNotNull(readBuffer, "parcEventBuffer_ReadFromFileDescriptor was passed a null buffer\n");
+// assertNotNull(readBuffer->evbuffer, "parcEventBuffer_ReadFromFileDescriptor was passed a null libevent evbuffer\n");
+
+ return evbuffer_read(readBuffer->evbuffer, fd, (int) length);
+}
+
+void
+parcEventBuffer_FreeLine(PARCEventBuffer *readBuffer, char **line)
+{
+ parcEventBuffer_OptionalAssertValid(readBuffer);
+// assertNotNull(readBuffer, "parcEventBuffer_ReadLine was passed a null readBuffer\n");
+// assertNotNull(readBuffer->evbuffer, "parcEventBuffer_ReadLine was passed a null libevent evbuffer\n");
+
+ parcMemory_Deallocate((void **) line);
+}
+
+char *
+parcEventBuffer_ReadLine(PARCEventBuffer *readBuffer, size_t *length)
+{
+ parcEventBuffer_OptionalAssertValid(readBuffer);
+// assertNotNull(readBuffer, "parcEventBuffer_ReadLine was passed a null readBuffer\n");
+// assertNotNull(readBuffer->evbuffer, "parcEventBuffer_ReadLine was passed a null libevent evbuffer\n");
+
+ return evbuffer_readln(readBuffer->evbuffer, length, EVBUFFER_EOL_CRLF);
+}
+
+int
+parcEventBuffer_AppendBuffer(PARCEventBuffer *source, PARCEventBuffer *destination)
+{
+ parcEventBuffer_OptionalAssertValid(source);
+ parcEventBuffer_OptionalAssertValid(destination);
+// assertNotNull(source, "parcEventBuffer_AppendBuffer was passed a null source parcEventBuffer\n");
+// assertNotNull(destination, "parcEventBuffer_AppendBuffer was passed a null destination parcEventBuffer\n");
+// assertNotNull(source->evbuffer, "parcEventBuffer_AppendBuffer was passed a null source libevent evbuffer\n");
+// assertNotNull(destination->evbuffer, "parcEventBuffer_AppendBuffer was passed a null destination libevent evbuffer\n");
+
+ return evbuffer_add_buffer(destination->evbuffer, source->evbuffer);
+}
+
+int
+parcEventBuffer_Append(PARCEventBuffer *parcEventBuffer, void *data, size_t length)
+{
+ parcEventBuffer_OptionalAssertValid(parcEventBuffer);
+// assertNotNull(parcEventBuffer, "parcEventBuffer_Append was passed a null parcEventBuffer\n");
+// assertNotNull(parcEventBuffer->evbuffer, "parcEventBuffer_Append was passed a null libevent evbuffer\n");
+ assertNotNull(data, "parcEventBuffer_Append was passed a null data buffer\n");
+
+ return evbuffer_add(parcEventBuffer->evbuffer, data, length);
+}
+
+int
+parcEventBuffer_Prepend(PARCEventBuffer *readBuffer, void *data, size_t length)
+{
+ parcEventBuffer_OptionalAssertValid(readBuffer);
+// assertNotNull(readBuffer->evbuffer, "parcEventBuffer_Prepend was passed a null libevent evbuffer\n");
+// assertNotNull(readBuffer, "parcEventBuffer_Prepend was passed a null buffer\n");
+ assertNotNull(data, "parcEventBuffer_Prepend was passed a null data buffer\n");
+
+ return evbuffer_prepend(readBuffer->evbuffer, data, length);
+}
+
+PARCEventBuffer *
+parcEventBuffer_GetQueueBufferInput(PARCEventQueue *queue)
+{
+ assertNotNull(queue, "parcEventBuffer_GetQueueBufferInput was passed a null queue\n");
+
+ PARCEventBuffer *parcEventBuffer = parcMemory_AllocateAndClear(sizeof(PARCEventBuffer));
+ assertNotNull(parcEventBuffer, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCEventBuffer));
+
+ parcEventBuffer->evbuffer = internal_parcEventQueue_GetEvInputBuffer(queue);
+ parcEventBuffer_LogDebug(parcEventBuffer, "parcEventBuffer_GetQueueBufferInput(queue=%p)\n", queue);
+
+ return parcEventBuffer;
+}
+
+PARCEventBuffer *
+parcEventBuffer_GetQueueBufferOutput(PARCEventQueue *queue)
+{
+ assertNotNull(queue, "parcEventBuffer_GetQueueBufferOutput was passed a null queue\n");
+
+ PARCEventBuffer *parcEventBuffer = parcMemory_AllocateAndClear(sizeof(PARCEventBuffer));
+ assertNotNull(parcEventBuffer, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCEventBuffer));
+
+ parcEventBuffer->evbuffer = internal_parcEventQueue_GetEvOutputBuffer(queue);
+ parcEventBuffer_LogDebug(parcEventBuffer, "parcEventBuffer_GetQueueBufferInput(queue=%p)\n", queue);
+
+ return parcEventBuffer;
+}
+
+void
+parcEventBuffer_EnableDebug(PARCLog *logger)
+{
+ parcEventBufferDebugLog = logger;
+}
+
+void
+parcEventBuffer_DisableDebug(void)
+{
+ parcEventBufferDebugLog = NULL;
+}
diff --git a/libparc/parc/algol/parc_EventBuffer.h b/libparc/parc/algol/parc_EventBuffer.h
new file mode 100755
index 00000000..8e82a5e6
--- /dev/null
+++ b/libparc/parc/algol/parc_EventBuffer.h
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_EventBuffer.h
+ * @ingroup events
+ * @brief Buffered event management
+ *
+ * Provides a facade implementing many regularly available event functions.
+ * This is an interface that software implementors may use to substitute
+ * different kinds of underlying implementations of these event management functions.
+ * Notable examples are libevent and libev.
+ *
+ */
+#ifndef libparc_parc_EventBuffer_h
+#define libparc_parc_EventBuffer_h
+
+#include <parc/algol/parc_EventQueue.h>
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcEventBuffer_OptionalAssertValid(_instance_)
+#else
+# define parcEventBuffer_OptionalAssertValid(_instance_) parcEventBuffer_AssertValid(_instance_)
+#endif
+
+/**
+ * @typedef PARCEventBuffer
+ * @brief A structure containing private libevent state data variables
+ */
+typedef struct PARCEventBuffer PARCEventBuffer;
+
+/**
+ * Create an event buffer instance.
+ *
+ * @returns A pointer to a new PARCEventBuffer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create();
+ * }
+ * @endcode
+ *
+ */
+PARCEventBuffer *parcEventBuffer_Create(void);
+
+/**
+ * Destroy a network parcEventBuffer instance.
+ *
+ * The address of the event instance is passed in.
+ *
+ * @param [in] parcEventBuffer - The address of the instance to destroy.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventBuffer_Destroy(&parcEventBuffer)
+ * }
+ * @endcode
+ *
+ */
+void parcEventBuffer_Destroy(PARCEventBuffer **parcEventBuffer);
+
+/**
+ * Determine if an instance of `PARCEventBuffer` 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] eventBuffer A pointer to a `PARCEventBuffer` instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventBuffer *instance = parcEventBuffer_Create();
+ *
+ * if (parcEventBuffer_IsValid(instance)) {
+ * printf("Instance is valid.\n");
+ * }
+ * }
+ * @endcode
+ */
+bool parcEventBuffer_IsValid(const PARCEventBuffer *eventBuffer);
+
+/**
+ * Assert that the given `PARCEventBuffer` instance is valid.
+ *
+ * @param [in] eventBuffer A pointer to a valid PARCEventBuffer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventBuffer *a = parcEventBuffer_Create();
+ *
+ * parcEventBuffer_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcEventBuffer_Release(&b);
+ * }
+ * @endcode
+ */
+void parcEventBuffer_AssertValid(const PARCEventBuffer *eventBuffer);
+
+/**
+ * Get the input parcEventBuffer instance from the Queue
+ *
+ * @param [in] parcEventQueue - The queue to obtain the input parcEventBuffer from
+ * @returns A pointer to the a PARCEventBuffer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventBuffer *parcEventBuffer = parcEventBuffer_GetQueueBufferInput(eventQueue);
+ * }
+ * @endcode
+ *
+ */
+PARCEventBuffer *parcEventBuffer_GetQueueBufferInput(PARCEventQueue *parcEventQueue);
+
+/**
+ * Get the output parcEventBuffer instance from the Queue
+ *
+ * @param [in] parcEventQueue - The queue to obtain the output parcEventBuffer from
+ * @returns A pointer to the a PARCEventBuffer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventBuffer *parcEventBuffer = parcEventBuffer_GetQueueBufferOutput(parcEventQueue);
+ * }
+ * @endcode
+ *
+ */
+PARCEventBuffer *parcEventBuffer_GetQueueBufferOutput(PARCEventQueue *parcEventQueue);
+
+/**
+ * Get the data length of the associated buffer
+ *
+ * @param [in] parcEventBuffer - The buffer to obtain the length from
+ * @returns The length of data within the buffer, 0 if the internal buffer has been freed
+ *
+ * Example:
+ * @code
+ * {
+ * int length = parcEventBuffer_GetLength(parcEventBuffer);
+ * }
+ * @endcode
+ *
+ */
+size_t parcEventBuffer_GetLength(PARCEventBuffer *parcEventBuffer);
+
+/**
+ * Consolidate data in the associated parcEventBuffer
+ *
+ * @param [in] parcEventBuffer - The buffer to consolidate
+ * @param [in] size - The length of data to consolidate, -1 linearizes the entire buffer
+ * @returns A pointer to the first byte in the buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * unsigned char *ptr = parcEventBuffer_Pullup(parcEventBuffer, size);
+ * }
+ * @endcode
+ *
+ */
+uint8_t *parcEventBuffer_Pullup(PARCEventBuffer *parcEventBuffer, ssize_t size);
+
+/**
+ * Read data from the associated parcEventBuffer
+ *
+ * @param [in] parcEventBuffer - The parcEventBuffer to read from
+ * @param [in] data - The memory to read into, NULL to discard data
+ * @param [in] length - The number of bytes of data to be read
+ * @returns Number of bytes read, -1 on failure.
+ *
+ * Example:
+ * @code
+ * {
+ * int bytesRead = parcEventBuffer_Read(parcEventBuffer, destination, bytesToRead);
+ * }
+ * @endcode
+ *
+ */
+int parcEventBuffer_Read(PARCEventBuffer *parcEventBuffer, void *data, size_t length);
+
+/**
+ * Read data from the associated parcEventBuffer without delete them from the buffer.
+ * Data can not be NULL
+ *
+ * @param [in] parcEventBuffer - The parcEventBuffer to read from
+ * @param [in] data - The memory to read into
+ * @param [in] length - The number of bytes of data to be read
+ * @returns Number of bytes read, -1 on failure.
+ *
+ */
+int parcEventBuffer_copyOut(PARCEventBuffer *readBuffer, void *data_out, size_t length);
+
+
+/**
+ * Read from a file descriptor into the end of a buffer
+ *
+ * @param [in] parcEventBuffer - The buffer to read from
+ * @param [in] fd - The file descriptor to read from
+ * @param [in] length - The number of bytes of data to be read
+ * @returns The number of bytes read, 0 on EOF and -1 on error.
+ *
+ * Example:
+ * @code
+ * {
+ * int bytesTransfered = parcEventBuffer_ReadFromFileDescriptor(parcEventBuffer, fd, length);
+ * }
+ * @endcode
+ *
+ */
+int parcEventBuffer_ReadFromFileDescriptor(PARCEventBuffer *parcEventBuffer, int fd, size_t length);
+
+/**
+ * Write to a file descriptor from a buffer
+ *
+ * @param [in] parcEventBuffer - The buffer to read from
+ * @param [in] fd - The file descriptor to write to
+ * @param [in] length - The number of bytes of data to be read (-1 for all).
+ * @returns The number of bytes read, 0 on EOF and -1 on error.
+ *
+ * Example:
+ * @code
+ * {
+ * int bytesTransfered = parcEventBuffer_WriteToFileDescriptor(parcEventBuffer, fd, length);
+ * }
+ * @endcode
+ *
+ */
+int parcEventBuffer_WriteToFileDescriptor(PARCEventBuffer *parcEventBuffer, int fd, ssize_t length);
+
+/**
+ * Append one PARCEventBuffer to another
+ *
+ * @param [in] source - The buffer to append
+ * @param [in] destination - The buffer to append to
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int result = parcEventBuffer_AppendBuffer(source, destination);
+ * }
+ * @endcode
+ *
+ */
+int parcEventBuffer_AppendBuffer(PARCEventBuffer *source, PARCEventBuffer *destination);
+
+/**
+ * Append bytes to a parcEventBuffer
+ *
+ * @param [in] parcEventBuffer - The buffer to write into
+ * @param [in] sourceData - The data to append
+ * @param [in] length - The number of bytes of data to be added
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int result = parcEventBuffer_Append(parcEventBuffer, sourceData, length);
+ * }
+ * @endcode
+ *
+ */
+int parcEventBuffer_Append(PARCEventBuffer *parcEventBuffer, void *sourceData, size_t length);
+
+/**
+ * Prepend data to the associated parcEventBuffer
+ *
+ * @param [in] parcEventBuffer - The parcEventBuffer to prepend to
+ * @param [in] sourceData - The data to prepend
+ * @param [in] length - The number of bytes of data to be added
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int result = parcEventBuffer_Read(parcEventBuffer, sourceData, length);
+ * }
+ * @endcode
+ *
+ */
+int parcEventBuffer_Prepend(PARCEventBuffer *parcEventBuffer, void *sourceData, size_t length);
+
+/**
+ * Move data from one buffer to another
+ *
+ * @param [in] sourceEventBuffer - The buffer to read from
+ * @param [in] destinationEventBuffer - The buffer to move into
+ * @param [in] length - The number of bytes of data to be moved
+ * @returns The number of bytes moved on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int bytesMoved = parcEventBuffer_Create(sourceEventBuffer, destinationEventBuffer, length);
+ * }
+ * @endcode
+ *
+ */
+int parcEventBuffer_ReadIntoBuffer(PARCEventBuffer *sourceEventBuffer, PARCEventBuffer *destinationEventBuffer, size_t length);
+
+/**
+ * Read a text line terminated by an optional carriage return, followed by a single linefeed
+ *
+ * @param [in] parcEventBuffer - The buffer to read from
+ * @param [in] length - The number of bytes of data to be moved
+ * @returns A newly allocated null terminated string, which must be freed by the caller
+ *
+ * Example:
+ * @code
+ * {
+ * char *text = parcEventBuffer_ReadLine(parcEventBuffer, length);
+ * ...
+ * parcMemory_Deallocate((void *)&text);
+ * }
+ * @endcode
+ *
+ */
+char *parcEventBuffer_ReadLine(PARCEventBuffer *parcEventBuffer, size_t *length);
+
+/**
+ * Free a text line returned from parcEventBuffer_ReadLine
+ *
+ * @param [in] parcEventBuffer - The buffer to read from
+ * @param [in] line address of returned value from previous call to parcEventBuffer_ReadLine
+ *
+ * Example:
+ * @code
+ * {
+ * char *text = parcEventBuffer_ReadLine(parcEventBuffer, length);
+ * ...
+ * parcEventBuffer_FreeLine(parcEventBuffer, &text);
+ * }
+ * @endcode
+ *
+ */
+void parcEventBuffer_FreeLine(PARCEventBuffer *parcEventBuffer, char **line);
+
+/**
+ * Turn on debugging flags and messages
+ *
+ * @param [in] logger - the log to write debug messages to
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventBuffer_EnableDebug(logger);
+ * }
+ * @endcode
+ *
+ */
+void parcEventBuffer_EnableDebug(PARCLog *logger);
+
+/**
+ * Turn off debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventBuffer_DisableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventBuffer_DisableDebug(void);
+#endif // libparc_parc_EventBuffer_h
diff --git a/libparc/parc/algol/parc_EventQueue.c b/libparc/parc/algol/parc_EventQueue.c
new file mode 100755
index 00000000..5d656a12
--- /dev/null
+++ b/libparc/parc/algol/parc_EventQueue.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 <errno.h>
+
+#include <LongBow/runtime.h>
+
+#include "internal_parc_Event.h"
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_EventQueue.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/logging/parc_Log.h>
+#include <parc/logging/parc_LogReporterFile.h>
+
+static int _parc_event_queue_debug_enabled = 0;
+
+#define parcEventQueue_LogDebug(parcEventQueue, ...) \
+ if (_parc_event_queue_debug_enabled) \
+ parcLog_Debug(parcEventScheduler_GetLogger(parcEventQueue->eventScheduler), __VA_ARGS__)
+
+/**
+ * Current implementation based on top of libevent2
+ */
+
+#include <event2/buffer.h>
+#include <event2/bufferevent.h>
+
+/**
+ * @typedef PARCEventQueue
+ * @brief A structure containing private event state
+ */
+struct PARCEventQueue {
+ // Event scheduler we have been queued with
+ PARCEventScheduler *eventScheduler;
+
+ struct bufferevent *buffereventBuffer;
+ // Interpose on bufferevent callbacks
+ PARCEventQueue_Callback *readCallback;
+ void *readUserData;
+ PARCEventQueue_Callback *writeCallback;
+ void *writeUserData;
+ PARCEventQueue_EventCallback *eventCallback;
+ void *eventUserData;
+};
+
+struct PARCEventQueuePair {
+ PARCEventQueue *up;
+ PARCEventQueue *down;
+};
+
+static void
+_parc_queue_read_callback(struct bufferevent *bev, void *ptr)
+{
+ PARCEventQueue *parcEventQueue = (PARCEventQueue *) ptr;
+ parcEventQueue_LogDebug(parcEventQueue,
+ "_parc_queue_read_callback(bev=%p,ptr->buffereventBuffer=%p,parcEventQueue=%p)\n",
+ bev, parcEventQueue->buffereventBuffer, parcEventQueue);
+ assertNotNull(parcEventQueue->readCallback, "parcEvent read callback called when NULL");
+
+ parcEventQueue->readCallback(parcEventQueue, PARCEventType_Read, parcEventQueue->readUserData);
+}
+
+static void
+_parc_queue_write_callback(struct bufferevent *bev, void *ptr)
+{
+ PARCEventQueue *parcEventQueue = (PARCEventQueue *) ptr;
+ parcEventQueue_LogDebug(parcEventQueue,
+ "_parc_queue_write_callback(bev=%p,ptr->buffereventBuffer=%p,parcEventQueue=%p)\n",
+ bev, parcEventQueue->buffereventBuffer, parcEventQueue);
+ assertNotNull(parcEventQueue->writeCallback, "parcEvent write callback called when NULL");
+
+ parcEventQueue->writeCallback(parcEventQueue, PARCEventType_Write, parcEventQueue->writeUserData);
+}
+
+static void
+_parc_queue_event_callback(struct bufferevent *bev, short events, void *ptr)
+{
+ PARCEventQueue *parcEventQueue = (PARCEventQueue *) ptr;
+ int errno_forwarded = errno;
+ parcEventQueue_LogDebug(parcEventQueue,
+ "_parc_queue_event_callback(bev=%p,events=%x,errno=%d,ptr->buffereventBuffer=%p,parcEventQueue=%p)\n",
+ bev, events, errno, parcEventQueue->buffereventBuffer, parcEventQueue);
+ assertNotNull(parcEventQueue->eventCallback, "parcEvent event callback called when NULL");
+
+ errno = errno_forwarded;
+ parcEventQueue->eventCallback(parcEventQueue, internal_bufferevent_type_to_PARCEventQueueEventType(events), parcEventQueue->eventUserData);
+}
+
+void
+parcEventQueue_SetCallbacks(PARCEventQueue *parcEventQueue,
+ PARCEventQueue_Callback *readCallback,
+ PARCEventQueue_Callback *writeCallback,
+ PARCEventQueue_EventCallback *eventCallback,
+ void *user_data)
+{
+ parcEventQueue_LogDebug(parcEventQueue,
+ "parcEventQueue_SetCallbacks(event=%p(buffer=%p),readcb=%p,writecb=%p,eventcb=%p,user_data=%p)\n",
+ parcEventQueue, parcEventQueue->buffereventBuffer,
+ readCallback, writeCallback, eventCallback,
+ user_data);
+
+ parcEventQueue->readCallback = readCallback;
+ parcEventQueue->readUserData = user_data;
+ parcEventQueue->writeCallback = writeCallback;
+ parcEventQueue->writeUserData = user_data;
+ parcEventQueue->eventCallback = eventCallback;
+ parcEventQueue->eventUserData = user_data;
+ bufferevent_setcb(parcEventQueue->buffereventBuffer,
+ (readCallback) ? _parc_queue_read_callback : NULL,
+ (writeCallback) ? _parc_queue_write_callback : NULL,
+ (eventCallback) ? _parc_queue_event_callback : NULL,
+ parcEventQueue);
+}
+
+PARCEventQueue *
+parcEventQueue_Create(PARCEventScheduler *eventScheduler, int fd, PARCEventQueueOption flags)
+{
+ assertNotNull(eventScheduler, "parcEventQueue_Create passed a NULL scheduler instance.");
+ PARCEventQueue *parcEventQueue = parcMemory_AllocateAndClear(sizeof(PARCEventQueue));
+ assertNotNull(parcEventQueue, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCEventQueue));
+ parcEventQueue->eventScheduler = eventScheduler;
+
+ //
+ // PARCEventQueue_CloseOnFree
+ // we close the underlying file descriptor/bufferevent/whatever
+ // when this bufferevent is freed.
+ //
+ // PARCEventQueue_DeferCallbacks
+ // callbacks are run deferred in the event loop.
+ //
+ parcEventQueue->buffereventBuffer = bufferevent_socket_new(parcEventScheduler_GetEvBase(eventScheduler), fd,
+ internal_PARCEventQueueOption_to_bufferevent_options(flags));
+ assertNotNull(parcEventQueue->buffereventBuffer,
+ "Got null from bufferevent_socket_new for socket %d", fd);
+
+ parcEventQueue_LogDebug(parcEventQueue,
+ "parcEventQueue_Create(eventScheduler=%p,libevent_base=%p) = %p\n",
+ eventScheduler,
+ parcEventScheduler_GetEvBase(eventScheduler),
+ parcEventQueue);
+
+ return parcEventQueue;
+}
+
+void
+parcEventQueue_Destroy(PARCEventQueue **parcEventQueue)
+{
+ parcEventQueue_LogDebug((*parcEventQueue), "parcEventQueue_Destroy(ptr=%p)\n", *parcEventQueue);
+ assertNotNull((*parcEventQueue)->buffereventBuffer, "parcEventQueue_Destroy passed a null buffer!");
+
+ bufferevent_free((*parcEventQueue)->buffereventBuffer);
+ parcMemory_Deallocate((void *) parcEventQueue);
+}
+
+int
+parcEventQueue_SetFileDescriptor(PARCEventQueue *parcEventQueue, int fd)
+{
+ return bufferevent_setfd(parcEventQueue->buffereventBuffer, fd);
+}
+
+int
+parcEventQueue_GetFileDescriptor(PARCEventQueue *parcEventQueue)
+{
+ return bufferevent_getfd(parcEventQueue->buffereventBuffer);
+}
+
+PARCEventType
+parcEventQueue_GetEnabled(PARCEventQueue *event)
+{
+ return internal_libevent_type_to_PARCEventType(bufferevent_get_enabled(event->buffereventBuffer));
+}
+
+void
+parcEventQueue_Enable(PARCEventQueue *parcEventQueue, PARCEventType types)
+{
+ bufferevent_enable(parcEventQueue->buffereventBuffer, internal_PARCEventType_to_libevent_type(types));
+}
+
+void
+parcEventQueue_Disable(PARCEventQueue *parcEventQueue, PARCEventType types)
+{
+ bufferevent_disable(parcEventQueue->buffereventBuffer, internal_PARCEventType_to_libevent_type(types));
+}
+
+int
+parcEventQueue_ConnectSocket(PARCEventQueue *instance, struct sockaddr *address, int addrlen)
+{
+ return bufferevent_socket_connect(instance->buffereventBuffer, address, addrlen);
+}
+
+int
+parcEventQueue_Flush(PARCEventQueue *parcEventQueue, PARCEventType types)
+{
+ return bufferevent_flush(parcEventQueue->buffereventBuffer, internal_PARCEventType_to_libevent_type(types), BEV_NORMAL);
+}
+
+int
+parcEventQueue_Finished(PARCEventQueue *parcEventQueue, PARCEventType types)
+{
+ return bufferevent_flush(parcEventQueue->buffereventBuffer, internal_PARCEventType_to_libevent_type(types), BEV_FINISHED);
+}
+
+void
+parcEventQueue_SetWatermark(PARCEventQueue *parcEventQueue, PARCEventType types, size_t low, size_t high)
+{
+ parcEventQueue_LogDebug(parcEventQueue, "parcEventQueue->buffereventBuffer=%p\n", parcEventQueue->buffereventBuffer);
+ bufferevent_setwatermark(parcEventQueue->buffereventBuffer, internal_PARCEventType_to_libevent_type(types), low, high);
+}
+
+int
+parcEventQueue_Printf(PARCEventQueue *parcEventQueue, const char *fmt, ...)
+{
+ struct evbuffer *buffer = bufferevent_get_output(parcEventQueue->buffereventBuffer);
+ assertNotNull(buffer, "bufferevent_get_output returned NULL");
+
+ va_list ap;
+
+ va_start(ap, fmt);
+ int result = evbuffer_add_vprintf(buffer, fmt, ap);
+ va_end(ap);
+ return result;
+}
+
+int
+parcEventQueue_Read(PARCEventQueue *parcEventQueue, void *data, size_t dataLength)
+{
+ return bufferevent_read(parcEventQueue->buffereventBuffer, data, dataLength);
+}
+
+int
+parcEventQueue_Write(PARCEventQueue *parcEventQueue, void *data, size_t dataLength)
+{
+ return bufferevent_write(parcEventQueue->buffereventBuffer, data, dataLength);
+}
+
+int
+parcEventQueue_SetPriority(PARCEventQueue *eventQueue, PARCEventPriority priority)
+{
+ bufferevent_priority_set(eventQueue->buffereventBuffer, internal_PARCEventPriority_to_libevent_priority(priority));
+ return 0;
+}
+
+PARCEventQueuePair *
+parcEventQueue_CreateConnectedPair(PARCEventScheduler *eventScheduler)
+{
+ assertNotNull(eventScheduler, "parcEventQueue_CreateConnectedPair must be passed a valid Event Scheduler");
+ PARCEventQueuePair *parcEventQueuePair = parcMemory_AllocateAndClear(sizeof(PARCEventQueuePair));
+ assertNotNull(parcEventQueuePair, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCEventQueuePair));
+
+ parcEventQueuePair->up = parcMemory_AllocateAndClear(sizeof(PARCEventQueue));
+ parcEventQueuePair->up->eventScheduler = eventScheduler;
+ parcEventQueue_LogDebug(parcEventQueuePair->up,
+ "up instance parcEventQueue_Create(eventScheduler=%p,libevent_parcEventQueue=%p) = %p\n",
+ eventScheduler,
+ parcEventScheduler_GetEvBase(eventScheduler),
+ parcEventQueuePair->up);
+ assertNotNull(parcEventQueuePair->up, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCEventQueue));
+
+ parcEventQueuePair->down = parcMemory_AllocateAndClear(sizeof(PARCEventQueue));
+ parcEventQueuePair->down->eventScheduler = eventScheduler;
+ parcEventQueue_LogDebug(parcEventQueuePair->down,
+ "down instance parcEventQueue_Create(eventScheduler=%p,libevent_parcEventQueue=%p) = %p\n",
+ eventScheduler,
+ parcEventScheduler_GetEvBase(eventScheduler),
+ parcEventQueuePair->down);
+ assertNotNull(parcEventQueuePair->down, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCEventQueue));
+
+ struct bufferevent *evpair[2];
+ int result = bufferevent_pair_new(parcEventScheduler_GetEvBase(eventScheduler), 0, evpair);
+ if (result != 0) {
+ parcMemory_Deallocate((void **) &(parcEventQueuePair->up));
+ parcMemory_Deallocate((void **) &(parcEventQueuePair->down));
+ parcMemory_Deallocate((void **) &parcEventQueuePair);
+ return NULL;
+ }
+
+ parcEventQueuePair->up->buffereventBuffer = evpair[0];
+ parcEventQueuePair->down->buffereventBuffer = evpair[1];
+
+ (void) parcEventQueue_SetPriority(parcEventQueuePair->up, PARCEventPriority_Normal);
+ (void) parcEventQueue_SetPriority(parcEventQueuePair->down, PARCEventPriority_Normal);
+
+ return parcEventQueuePair;
+}
+
+void
+parcEventQueue_DestroyConnectedPair(PARCEventQueuePair **queuePair)
+{
+ parcEventQueue_LogDebug((*queuePair)->up,
+ "parcEventQueue_DestroyPair(up ptr=%p)\n",
+ (*queuePair)->up);
+ parcEventQueue_LogDebug((*queuePair)->down,
+ "parcEventQueue_DestroyPair(down ptr=%p)\n",
+ (*queuePair)->down);
+
+ bufferevent_free((*queuePair)->up->buffereventBuffer);
+ bufferevent_free((*queuePair)->down->buffereventBuffer);
+
+ parcMemory_Deallocate((void **) &((*queuePair)->up));
+ parcMemory_Deallocate((void **) &((*queuePair)->down));
+ parcMemory_Deallocate((void **) queuePair);
+}
+
+PARCEventQueue *
+parcEventQueue_GetConnectedUpQueue(PARCEventQueuePair *queuePair)
+{
+ return queuePair->up;
+}
+
+PARCEventQueue *
+parcEventQueue_GetConnectedDownQueue(PARCEventQueuePair *queuePair)
+{
+ return queuePair->down;
+}
+
+struct evbuffer *
+internal_parcEventQueue_GetEvInputBuffer(PARCEventQueue *queue)
+{
+ return bufferevent_get_input(queue->buffereventBuffer);
+}
+
+struct evbuffer *
+internal_parcEventQueue_GetEvOutputBuffer(PARCEventQueue *queue)
+{
+ return bufferevent_get_output(queue->buffereventBuffer);
+}
+
+void
+parcEventQueue_EnableDebug(void)
+{
+ _parc_event_queue_debug_enabled = 1;
+}
+
+void
+parcEventQueue_DisableDebug(void)
+{
+ _parc_event_queue_debug_enabled = 0;
+}
diff --git a/libparc/parc/algol/parc_EventQueue.h b/libparc/parc/algol/parc_EventQueue.h
new file mode 100644
index 00000000..282df302
--- /dev/null
+++ b/libparc/parc/algol/parc_EventQueue.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 parc_EventQueue.h
+ * @ingroup events
+ * @brief Queue buffer events
+ *
+ * Provides a facade implementing many regularly available event functions.
+ * This is an interface that software implementors may use to substitute
+ * different kinds of underlying implementations of these event management functions.
+ * Notable examples are libevent and libev.
+ *
+ */
+#ifndef libparc_parc_EventQueue_h
+#define libparc_parc_EventQueue_h
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <parc/algol/parc_Event.h>
+
+/**
+ * Current implementation based on top of libevent2
+ */
+
+/**
+ * @typedef PARCEventQueue
+ * @brief A structure containing private libevent state data variables
+ */
+typedef struct PARCEventQueue PARCEventQueue;
+
+/**
+ * @typedef PARCEventQueuePair
+ * @brief A structure containing private libevent state data for connected queue pairs
+ */
+typedef struct PARCEventQueuePair PARCEventQueuePair;
+
+/**
+ * @typedef PARCEventQueueEventType
+ * @brief An enumeration of queue event types
+ */
+typedef enum {
+ PARCEventQueueEventType_Reading = 0x01,
+ PARCEventQueueEventType_Writing = 0x02,
+ PARCEventQueueEventType_EOF = 0x10,
+ PARCEventQueueEventType_Error = 0x20,
+ PARCEventQueueEventType_Timeout = 0x40,
+ PARCEventQueueEventType_Connected = 0x80
+} PARCEventQueueEventType;
+
+/**
+ * @typedef PARCEventQueue_Options
+ * @brief A structure queue flags
+ */
+typedef enum {
+ PARCEventQueueOption_CloseOnFree = 0x01,
+ PARCEventQueueOption_DeferCallbacks = 0x04
+} PARCEventQueueOption;
+
+/**
+ * @typedef PARCEventQueue_Callback
+ * @brief A definition for callback function arguments
+ */
+typedef void (PARCEventQueue_Callback)(PARCEventQueue *event, PARCEventType type, void *user_data);
+
+/**
+ * @typedef PARCEventQueue_EventCallback
+ * @brief A definition for callback function arguments
+ */
+typedef void (PARCEventQueue_EventCallback)(PARCEventQueue *event, PARCEventQueueEventType type, void *user_data);
+
+/**
+ * Create a buffer event handler instance.
+ *
+ * The event instance is passed in. Options can be either, both or none of the following.
+ *
+ * PARCEventQueue_CloseOnFree
+ * The underlying file descriptor is closed when this event is freed.
+ *
+ * PARCEventQueue_DeferCallbacks
+ * Callbacks are run deferred in the scheduler.
+ *
+ * @param [in] eventScheduler - The scheduler instance base.
+ * @param [in] fd the file descriptor to monitor
+ * @param [in] options as described in flags above
+ * @returns A pointer to the a PARCEventQueue instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventQueue *event = parcEventQueue_Create(eventScheduler, fd, PARCEventQueue_CloseOnFree);
+ * }
+ * @endcode
+ *
+ */
+PARCEventQueue *parcEventQueue_Create(PARCEventScheduler *eventScheduler, int fd, PARCEventQueueOption options);
+
+/**
+ * Destroy a buffer event handler instance.
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] eventQueue - The address of the instance to destroy.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventQueue_Destroy(&eventQueue);
+ * }
+ * @endcode
+ *
+ */
+void parcEventQueue_Destroy(PARCEventQueue **eventQueue);
+
+/**
+ * Enable events on an instance.
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] event - queue instance to enable.
+ * @param [in] types - the event(s) to enable.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventQueue_Enable(bufferEvent, PARCEvent_ReadEvent);
+ * }
+ * @endcode
+ *
+ */
+void parcEventQueue_Enable(PARCEventQueue *event, PARCEventType types);
+
+/**
+ * Get enable events on an instance.
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] queue - the instance to return enabled events from
+ * @returns mask of events which are enabled.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventType *events = parcEventQueue_GetEnable(queue);
+ * }
+ * @endcode
+ *
+ */
+PARCEventType parcEventQueue_GetEnabled(PARCEventQueue *queue);
+
+/**
+ * Disable events on an instance.
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] queue - instance to disable event on.
+ * @param [in] types - the events to disable.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventQueue_Disable(queue, types);
+ * }
+ * @endcode
+ *
+ */
+void parcEventQueue_Disable(PARCEventQueue *queue, PARCEventType types);
+
+/**
+ * Set callbacks on a buffer event instance.
+ *
+ * The event instance is passed in.
+ * You can disable a callback by passing NULL instead of the callback function.
+ * NB: all the callback functions on a bufferevent share a single user_data
+ * value, so changing user_data will affect all of them.
+ *
+ * @param [in] eventInstance - event instance
+ * @param [in] readCallback - callback for read events
+ * @param [in] writeCallback - callback for write events
+ * @param [in] eventCallback - callback for non-read/write events
+ * @param [in] user_data - data passed along in callback arguments
+ *
+ * Example:
+ * @code
+ * void Callback(PARCEventType type, void *user_data)
+ * {
+ * printf("Received event of type=%d\n", type);
+ * }
+ * ...
+ * {
+ * ...
+ * parcEventQueue_SetCallbacks(eventInstance, Callback, NULL, NULL, user_data);
+ * parcEventQueue_Enable(eventInstance, PARCEventType_Read);
+ * }
+ * @endcode
+ *
+ */
+void parcEventQueue_SetCallbacks(PARCEventQueue *eventInstance,
+ PARCEventQueue_Callback *readCallback,
+ PARCEventQueue_Callback *writeCallback,
+ PARCEventQueue_EventCallback *eventCallback,
+ void *user_data);
+
+/**
+ * Flush events on a queue
+ *
+ * @param [in] queue instance to flush
+ * @param [in] types the type(s) of events to flush
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int result = parcEventQueue_Flush(queue, PARCEventType_Write);
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_Flush(PARCEventQueue *queue, PARCEventType types);
+
+/**
+ * Finialized flush of events on a queue
+ *
+ * @param [in] queue instance to flush
+ * @param [in] types the type(s) of events to flush
+ * @returns 0 if no data was flushed, 1 if some data was flushed, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int result = parcEventQueue_Finished(queue, PARCEventType_Write);
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_Finished(PARCEventQueue *queue, PARCEventType types);
+
+/**
+ * Set watermark boundries on a queue
+ *
+ * @param [in] queue - queue instance to set watermark on
+ * @param [in] types - the events to set watermark on
+ * @param [in] low - the low watermark value
+ * @param [in] high - the high watermark value
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventQueue_SetWatermark(queue, PARCEventType_Read, 0, MAXPATHLEN);
+ * }
+ * @endcode
+ *
+ */
+void parcEventQueue_SetWatermark(PARCEventQueue *queue, PARCEventType types, size_t low, size_t high);
+
+/**
+ * Add formatted text to the end of a queue
+ *
+ * @param [in] queue - queue instance to write to
+ * @param [in] fmt - printf arguments
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventQueue_Printf(queue, "%s\n", "Hello world.");
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_Printf(PARCEventQueue *queue, const char *fmt, ...);
+
+/**
+ * Set the associated file descriptor on a queue
+ *
+ * @param [in] queue instance set to monitor this descriptor
+ * @param [in] fd file descriptor
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int result = parcEventQueue_SetFileDescriptor(queue, STDIN_FILENO);
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_SetFileDescriptor(PARCEventQueue *queue, int fd);
+
+/**
+ * Get the associated file descriptor on a queue
+ *
+ * @param [in] queue instance set to monitor this descriptor
+ * @returns file descriptor on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int fileDescriptor = parcEventQueue_GetFileDescriptor(queue);
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_GetFileDescriptor(PARCEventQueue *queue);
+
+/**
+ * Read data from the queue output
+ *
+ * @param [in] queue instance to read from
+ * @param [in] data to read into
+ * @param [in] dataLength length of data to read
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int result = parcEventQueue_Read(queue, data, length);
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_Read(PARCEventQueue *queue, void *data, size_t dataLength);
+
+/**
+ * Add data to the queue output
+ *
+ * @param [in] queue instance to add to
+ * @param [in] data to write
+ * @param [in] dataLength length of data to write
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * int result = parcEventQueue_Write(queue, data, length);
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_Write(PARCEventQueue *queue, void *data, size_t dataLength);
+
+/**
+ * Attach an launch a socket on a queue
+ *
+ * @param [in] queue instance to attach socket to
+ * @param [in] address socket data
+ * @param [in] addressLength socket data length
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * struct sockaddr_un addr_unix;
+ * memset(&addr_unix, 0, sizeof(addr_unix));
+ * addr_unix.sun_family = AF_UNIX;
+ * strcpy(addr_unix.sun_path, sock_name);
+ * int result = parcEventQueue_ConnectSocket(queue, addr_unix, sizeof(addr_unix));
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_ConnectSocket(PARCEventQueue *queue, struct sockaddr *address, int addressLength);
+
+/**
+ * Set queue priority
+ *
+ * @param [in] queue instance to modify
+ * @param [in] priority queue priority
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * parcEvent_Enable(queue, PARCEventQueuePriority_Normal);
+ * }
+ * @endcode
+ *
+ */
+int parcEventQueue_SetPriority(PARCEventQueue *queue, PARCEventPriority priority);
+
+/**
+ * Create a pair of connected queues
+ *
+ * @param [in] eventScheduler event scheduler instance
+ * @returns a queue pair instance
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventQueuePair *pair = parcEventQueue_CreateConnectedPair(eventScheduler);
+ * }
+ * @endcode
+ *
+ */
+PARCEventQueuePair *parcEventQueue_CreateConnectedPair(PARCEventScheduler *eventScheduler);
+
+/**
+ * Destroy a connected queue pair
+ *
+ * @param [in] queuePair queue pair instance address to destroy
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventQueuePairCreateparcEventQueue_DestroyConnectedPair(&queuePair);
+ * }
+ * @endcode
+ *
+ */
+void parcEventQueue_DestroyConnectedPair(PARCEventQueuePair **queuePair);
+
+/**
+ * Return the downward queue of a pair
+ *
+ * @param [in] queuePair queue pair instance address to destroy
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventQueue *downQueue = parcEventQueue_GetConnectedDownQueue(queuePair);
+ * }
+ * @endcode
+ *
+ */
+PARCEventQueue *parcEventQueue_GetConnectedDownQueue(PARCEventQueuePair *queuePair);
+
+/**
+ * Return the upward queue of a pair
+ *
+ * @param [in] queuePair queue pair instance address to destroy
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventQueue *upQueue = parcEventQueue_GetConnectedUpQueue(queuePair);
+ * }
+ * @endcode
+ *
+ */
+PARCEventQueue *parcEventQueue_GetConnectedUpQueue(PARCEventQueuePair *queuePair);
+
+/**
+ * Private Internal Function - return internal input buffer of a queue
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] queue the event queue
+ * @returns private evbuffer pointer
+ *
+ * Example:
+ * @code
+ * {
+ * struct evbuffer *evbuffer = internal_parcEventQueue_GetEvInputBuffer(queue);
+ * }
+ * @endcode
+ *
+ */
+struct evbuffer *internal_parcEventQueue_GetEvInputBuffer(PARCEventQueue *queue);
+
+/**
+ * Private Internal Function - return internal output buffer of a queue
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] queue the event queue
+ * @returns private evbuffer pointer
+ *
+ * Example:
+ * @code
+ * {
+ * struct evbuffer *evbuffer = internal_parcEventQueue_GetEvOutputBuffer(queue);
+ * }
+ * @endcode
+ *
+ */
+struct evbuffer *internal_parcEventQueue_GetEvOutputBuffer(PARCEventQueue *queue);
+
+/**
+ * Turn on debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventQueue_EnableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventQueue_EnableDebug(void);
+
+/**
+ * Turn off debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventQueue_DisableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventQueue_DisableDebug(void);
+#endif // libparc_parc_EventQueue_h
diff --git a/libparc/parc/algol/parc_EventScheduler.c b/libparc/parc/algol/parc_EventScheduler.c
new file mode 100755
index 00000000..55de5c52
--- /dev/null
+++ b/libparc/parc/algol/parc_EventScheduler.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "internal_parc_Event.h"
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/logging/parc_Log.h>
+#include <parc/logging/parc_LogReporterFile.h>
+
+/**
+ * Current implementation based on top of libevent2
+ */
+#include <event2/event.h>
+
+static int _parc_event_scheduler_debug_enabled = 0;
+
+#define parcEventScheduler_LogDebug(parcEventScheduler, ...) \
+ if (_parc_event_scheduler_debug_enabled) \
+ parcLog_Debug(parcEventScheduler->log, __VA_ARGS__)
+
+struct PARCEventScheduler {
+ /**
+ * Base of the libevent manager.
+ */
+ struct event_base *evbase;
+ PARCLog *log;
+};
+
+static PARCLog *
+_parc_logger_create(void)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ parcOutputStream_Release(&output);
+
+ PARCLog *log = parcLog_Create("localhost", "test_parc_Log", NULL, reporter);
+ parcLogReporter_Release(&reporter);
+
+ parcLog_SetLevel(log, PARCLogLevel_All);
+ return log;
+}
+
+void *
+parcEventScheduler_GetEvBase(PARCEventScheduler *parcEventScheduler)
+{
+ return (void *) parcEventScheduler->evbase;
+}
+
+PARCEventScheduler *
+parcEventScheduler_Create(void)
+{
+ internal_parc_initializeLibevent();
+
+ PARCEventScheduler *parcEventScheduler = parcMemory_Allocate(sizeof(PARCEventScheduler));
+ assertNotNull(parcEventScheduler, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCEventScheduler));
+
+ // Initialize libevent base pointer.
+ parcEventScheduler->evbase = event_base_new();
+
+ assertNotNull(parcEventScheduler->evbase, "Could not obtain an event base!");
+ int result = event_base_priority_init(parcEventScheduler->evbase, PARCEventPriority_NumberOfPriorities);
+ assertTrue(result == 0, "Could not set scheduler priorities (%d)", result);
+
+ parcEventScheduler->log = _parc_logger_create();
+ assertNotNull(parcEventScheduler->log, "Could not create parc logger");
+
+ parcEventScheduler_LogDebug(parcEventScheduler, "parcEventScheduler_Create() = %p\n", parcEventScheduler);
+
+ return parcEventScheduler;
+}
+
+int
+parcEventScheduler_Start(PARCEventScheduler *parcEventScheduler, PARCEventSchedulerDispatchType type)
+{
+ parcEventScheduler_LogDebug(parcEventScheduler, "parcEventScheduler_Start(%p, %d)\n", parcEventScheduler, type);
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Start must be passed a valid base parcEventScheduler!");
+ int result = event_base_loop(parcEventScheduler->evbase,
+ internal_PARCEventSchedulerDispatchType_to_eventloop_options(type));
+ return result;
+}
+
+int
+parcEventScheduler_DispatchBlocking(PARCEventScheduler *parcEventScheduler)
+{
+ return parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+}
+
+int
+parcEventScheduler_DispatchNonBlocking(PARCEventScheduler *parcEventScheduler)
+{
+ return parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_NonBlocking);
+}
+
+int
+parcEventScheduler_Stop(PARCEventScheduler *parcEventScheduler, struct timeval *delay)
+{
+ parcEventScheduler_LogDebug(parcEventScheduler, "parcEventScheduler_Stop(%p, %p)\n", parcEventScheduler, delay);
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Stop must be passed a valid base parcEventScheduler!");
+ int result = event_base_loopexit(parcEventScheduler->evbase, delay);
+ return result;
+}
+
+int
+parcEventScheduler_Abort(PARCEventScheduler *parcEventScheduler)
+{
+ parcEventScheduler_LogDebug(parcEventScheduler, "parcEventScheduler_Abort(%p)\n", parcEventScheduler);
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Abort must be passed a valid base parcEventScheduler!");
+ int result = event_base_loopbreak(parcEventScheduler->evbase);
+ return result;
+}
+
+static int _event_enable_debug_mode_called = 0;
+
+void
+parcEventScheduler_EnableDebug(void)
+{
+ _parc_event_scheduler_debug_enabled = 1;
+ if (_event_enable_debug_mode_called == 0) {
+ event_enable_debug_mode();
+ _event_enable_debug_mode_called = 1;
+ }
+}
+
+void
+parcEventScheduler_DisableDebug(void)
+{
+ _parc_event_scheduler_debug_enabled = 0;
+}
+
+void
+parcEventScheduler_Destroy(PARCEventScheduler **parcEventScheduler)
+{
+ parcEventScheduler_LogDebug((*parcEventScheduler), "parcEventScheduler_Destroy(%p)\n", *parcEventScheduler);
+
+ assertNotNull(*parcEventScheduler, "parcEventScheduler_Destroy must be passed a valid base parcEventScheduler!");
+ assertNotNull((*parcEventScheduler)->evbase, "parcEventScheduler_Destroy passed a NULL event base member!");
+
+ event_base_free((*parcEventScheduler)->evbase);
+ parcLog_Release(&((*parcEventScheduler)->log));
+ parcMemory_Deallocate((void **) parcEventScheduler);
+}
+
+PARCLog *
+parcEventScheduler_GetLogger(PARCEventScheduler *parcEventScheduler)
+{
+ return parcEventScheduler->log;
+}
diff --git a/libparc/parc/algol/parc_EventScheduler.h b/libparc/parc/algol/parc_EventScheduler.h
new file mode 100644
index 00000000..d84ac5e4
--- /dev/null
+++ b/libparc/parc/algol/parc_EventScheduler.h
@@ -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.
+ */
+
+/**
+ * @file parc_EventScheduler.h
+ * @ingroup events
+ * @brief Event scheduler
+ *
+ * Provides a facade implementing many regularly available event functions.
+ * This is an interface that software implementors may use to substitute
+ * different kinds of underlying implementations of these event management functions.
+ * Notable examples are libevent and libev.
+ *
+ */
+#ifndef libparc_parc_EventScheduler_h
+#define libparc_parc_EventScheduler_h
+
+#include <stdlib.h>
+#include <stdint.h>
+
+/*
+ * Currently implemented using libevent
+ */
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/logging/parc_Log.h>
+
+/**
+ * @typedef PARCEventScheduler
+ * @brief A structure containing private event state
+ */
+struct PARCEventScheduler;
+typedef struct PARCEventScheduler PARCEventScheduler;
+
+typedef enum {
+ PARCEventSchedulerDispatchType_Blocking = 0x00,
+ PARCEventSchedulerDispatchType_LoopOnce = 0x01,
+ PARCEventSchedulerDispatchType_NonBlocking = 0x02,
+} PARCEventSchedulerDispatchType;
+
+/**
+ * Create a new parcEventScheduler instance.
+ *
+ * A new parcEventScheduler instance is returned.
+ *
+ * @returns A pointer to the a PARCEvent instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEvent *parcEventScheduler = parcEvent_Create();
+ * }
+ * @endcode
+ *
+ */
+PARCEventScheduler *parcEventScheduler_Create(void);
+
+/**
+ * Start the event eventScheduler
+ *
+ * @param [in] parcEventScheduler - The parcEventScheduler instance to start.
+ * @param type - The mode of dispatch for this `PARCEventScheduler` instance.
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * result = parcEventScheduler_Start(parcEventScheduler, PARCEventScheduler_Blocking);
+ * }
+ * @endcode
+ *
+ */
+int parcEventScheduler_Start(PARCEventScheduler *parcEventScheduler, PARCEventSchedulerDispatchType type);
+
+/**
+ * Dispatch the event scheduler to process any pending events, blocking until
+ * some events have been triggered and then processed.
+ *
+ * @param [in] parcEventScheduler - The parcEventScheduler instance to run.
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * result = parcEventScheduler_DispatchBlocking(parcEventScheduler, PARCEventScheduler_Blocking);
+ * }
+ * @endcode
+ */
+int parcEventScheduler_DispatchBlocking(PARCEventScheduler *parcEventScheduler);
+
+/**
+ * Dispatch the event scheduler to process any pending events.
+ *
+ * If there are no pending events then the function will immediately return.
+ *
+ * @param [in] parcEventScheduler - The parcEventScheduler instance to run.
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * result = parcEventScheduler_DispatchNonBlocking(parcEventScheduler, PARCEventScheduler_Blocking);
+ * }
+ * @endcode
+ *
+ */
+int parcEventScheduler_DispatchNonBlocking(PARCEventScheduler *parcEventScheduler);
+
+/**
+ * Stop the event parcEventScheduler
+ *
+ * @param [in] parcEventScheduler instance to stop scheduling.
+ * @param [in] delay time to wait before stopping, 0 for stop now
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * result = parcEventScheduler_Stop(parcEventScheduler, timeout);
+ * }
+ * @endcode
+ *
+ */
+int parcEventScheduler_Stop(PARCEventScheduler *parcEventScheduler, struct timeval *delay);
+
+/**
+ * Immediately abort the event parcEventScheduler
+ *
+ * @param [in] parcEventScheduler instance to abort scheduling.
+ * @returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * {
+ * result = parcEventScheduler_Abort(parcEventScheduler);
+ * }
+ * @endcode
+ *
+ */
+int parcEventScheduler_Abort(PARCEventScheduler *parcEventScheduler);
+
+/**
+ * Destroy a parcEventScheduler instance.
+ *
+ * The address of the parcEventScheduler instance is passed in.
+ *
+ * @param [in] parcEventScheduler address of instance to destroy.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventScheduler_Destroy(&parcEventScheduler);
+ * }
+ * @endcode
+ *
+ */
+void parcEventScheduler_Destroy(PARCEventScheduler **parcEventScheduler);
+
+/**
+ * Turn on debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventScheduler_EnableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventScheduler_EnableDebug(void);
+
+/**
+ * Turn off debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventScheduler_DisableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventScheduler_DisableDebug(void);
+
+/**
+ * Internal libevent data accessor function.
+ *
+ * THIS IS FOR INTERNAL USE ONLY. USE WITH CAUTION.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventScheduler_GetEvBase(parcEventScheduler);
+ * }
+ * @endcode
+ *
+ */
+void *parcEventScheduler_GetEvBase(PARCEventScheduler *parcEventScheduler);
+
+/**
+ * Logger accessor function
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLog *logger = parcEventScheduler_GetLogger(parcEventScheduler);
+ * }
+ * @endcode
+ *
+ */
+PARCLog *parcEventScheduler_GetLogger(PARCEventScheduler *parcEventScheduler);
+#endif // libparc_parc_EventScheduler_h
diff --git a/libparc/parc/algol/parc_EventSignal.c b/libparc/parc/algol/parc_EventSignal.c
new file mode 100755
index 00000000..7b8d1191
--- /dev/null
+++ b/libparc/parc/algol/parc_EventSignal.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 <LongBow/runtime.h>
+
+#include "internal_parc_Event.h"
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_EventSignal.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/logging/parc_Log.h>
+#include <parc/logging/parc_LogReporterFile.h>
+
+static int _parc_event_signal_debug_enabled = 0;
+
+#define parcEventSignal_LogDebug(parcEventSignal, ...) \
+ if (_parc_event_signal_debug_enabled) \
+ parcLog_Debug(parcEventScheduler_GetLogger(parcEventSignal->eventScheduler), __VA_ARGS__)
+
+/**
+ * Current implementation based on top of libevent2
+ */
+#include <event2/event.h>
+#include <event2/util.h>
+
+struct PARCEventSignal {
+ /**
+ * The event instance.
+ */
+ struct event *event;
+
+ // Event scheduler we have been queued with
+ PARCEventScheduler *eventScheduler;
+
+ PARCEventSignal_Callback *callback;
+ void *callbackUserData;
+};
+
+static void
+_parc_event_signal_callback(evutil_socket_t fd, short flags, void *context)
+{
+ PARCEventSignal *parcEventSignal = (PARCEventSignal *) context;
+ parcEventSignal_LogDebug(parcEventSignal,
+ "_parc_event_signal_callback(fd=%x,flags=%x,parcEventSignal=%p)\n",
+ fd, flags, parcEventSignal);
+ parcEventSignal->callback((int) fd, internal_libevent_type_to_PARCEventType(flags),
+ parcEventSignal->callbackUserData);
+}
+
+PARCEventSignal *
+parcEventSignal_Create(PARCEventScheduler *eventScheduler, int signal, PARCEventType flags, PARCEvent_Callback *callback, void *callbackArgs)
+{
+ PARCEventSignal *parcEventSignal = parcMemory_Allocate(sizeof(PARCEventSignal));
+ assertNotNull(parcEventSignal, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCEventSignal));
+
+ parcEventSignal->eventScheduler = eventScheduler;
+ parcEventSignal->callback = callback;
+ parcEventSignal->callbackUserData = callbackArgs;
+
+ parcEventSignal->event = event_new(parcEventScheduler_GetEvBase(eventScheduler), signal,
+ internal_PARCEventType_to_libevent_type(flags),
+ _parc_event_signal_callback, parcEventSignal);
+ assertNotNull(parcEventSignal->event, "Could not create a new event!");
+
+ parcEventSignal_LogDebug(parcEventSignal,
+ "parcEventSignal_Create(base=%p,signal=%x,flags=%x,cb=%p,args=%p) = %p\n",
+ parcEventScheduler_GetEvBase(eventScheduler), signal, flags,
+ callback, callbackArgs, parcEventSignal);
+ return parcEventSignal;
+}
+
+int
+parcEventSignal_Start(PARCEventSignal *parcEventSignal)
+{
+ parcEventSignal_LogDebug(parcEventSignal, "parcEventSignal_Start(event=%p)\n", parcEventSignal);
+ assertNotNull(parcEventSignal, "parcEventStart_Signal must be passed a valid event!");
+
+ int result = event_add(parcEventSignal->event, NULL);
+ return result;
+}
+
+int
+parcEventSignal_Stop(PARCEventSignal *parcEventSignal)
+{
+ parcEventSignal_LogDebug(parcEventSignal, "parcEventSignal_Stop(event=%p)\n", parcEventSignal);
+ assertNotNull(parcEventSignal, "parcEvent_Stop must be passed a valid event!");
+
+ int result = event_del(parcEventSignal->event);
+ return result;
+}
+
+void
+parcEventSignal_Destroy(PARCEventSignal **parcEventSignal)
+{
+ parcEventSignal_LogDebug((*parcEventSignal), "parcEventSignal_Destroy(event=%p)\n", parcEventSignal);
+ assertNotNull(*parcEventSignal, "parcEvent_Destroy must be passed a valid parcEventSignal!");
+ assertNotNull((*parcEventSignal)->event, "parcEvent_Destroy passed a null event!");
+ event_free((*parcEventSignal)->event);
+ parcMemory_Deallocate((void **) parcEventSignal);
+}
+
+void
+parcEventSignal_EnableDebug(void)
+{
+ _parc_event_signal_debug_enabled = 1;
+}
+
+void
+parcEventSignal_DisableDebug(void)
+{
+ _parc_event_signal_debug_enabled = 0;
+}
diff --git a/libparc/parc/algol/parc_EventSignal.h b/libparc/parc/algol/parc_EventSignal.h
new file mode 100755
index 00000000..e289f506
--- /dev/null
+++ b/libparc/parc/algol/parc_EventSignal.h
@@ -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.
+ */
+
+/**
+ * @file parc_EventSignal.h
+ * @ingroup events
+ * @brief Signal events
+ *
+ * Provides a facade implementing many regularly available event functions.
+ * This is an interface that software implementors may use to substitute
+ * different kinds of underlying implementations of these event management functions.
+ * Notable examples are libevent and libev.
+ *
+ */
+#ifndef libparc_parc_EventSignal
+#define libparc_parc_EventSignal
+
+#include <parc/algol/parc_Event.h>
+
+typedef void (PARCEventSignal_Callback)(int fd, PARCEventType type, void *user_data);
+
+typedef struct PARCEventSignal PARCEventSignal;
+
+/**
+ * Create a new signal event instance.
+ *
+ * The new event instance is returned.
+ *
+ * @param [in] parcEventScheduler - scheduler instance
+ * @param [in] signal - signal to catch
+ * @param [in] flags - event flags
+ * @param [in] callback - event callback
+ * @param [in] callbackArguments - private arguments passed to callback
+ * @returns A pointer to the a PARCEventSignal instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventSignal *parcEventSignal = parcEventSignal_Create(parcEventScheduler, SIGUSR1, 0, callback, callbackArguments);
+ * }
+ * @endcode
+ *
+ */
+PARCEventSignal *parcEventSignal_Create(PARCEventScheduler *parcEventScheduler,
+ int signal, PARCEventType flags,
+ PARCEventSignal_Callback *callback,
+ void *callbackArguments);
+
+/**
+ * Prepare a parcEventSignal instance to be scheduled.
+ *
+ * @returns -1 on error, 0 on success if nothing changed in the event backend, and 1 on success if something did.
+ * @param [in] parcEventSignal the newly created event instance.
+ *
+ * Example:
+ * @code
+ * addEvent(PARCEventSignal *parcEventSignal)
+ * {
+ * int result = parcEventSignal_Start(parcEventSignal);
+ * }
+ * @endcode
+ *
+ */
+int parcEventSignal_Start(PARCEventSignal *parcEventSignal);
+
+/**
+ * Stop a parcEventSignal instance.
+ *
+ * @param [in] parcEventSignal - The newly created event instance.
+ *
+ * Example:
+ * @code
+ * removeEvent(PARCEventSignal *parcEventSignal)
+ * {
+ * parcEventSignal_Stop(parcEventSignal);
+ * }
+ * @endcode
+ *
+ */
+int parcEventSignal_Stop(PARCEventSignal *parcEventSignal);
+
+/**
+ * Destroy a parcEventSignal instance.
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] parcEventSignal The instance to destroy.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventSignal_Destroy(&eparcEventSignal vent);
+ * }
+ * @endcode
+ *
+ */
+void parcEventSignal_Destroy(PARCEventSignal **parcEventSignal);
+
+/**
+ * Turn on debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventSignal_EnableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventSignal_EnableDebug(void);
+
+/**
+ * Turn off debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventSignal_DisableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventSignal_DisableDebug(void);
+#endif // libparc_parc_EventSignal_h
diff --git a/libparc/parc/algol/parc_EventSocket.c b/libparc/parc/algol/parc_EventSocket.c
new file mode 100755
index 00000000..dcb2fd69
--- /dev/null
+++ b/libparc/parc/algol/parc_EventSocket.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 <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_EventSocket.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/logging/parc_Log.h>
+#include <parc/logging/parc_LogReporterFile.h>
+
+static int _parc_event_socket_debug_enabled = 0;
+
+#define parcEventSocket_LogDebug(parcEventSocket, ...) \
+ if (_parc_event_socket_debug_enabled) \
+ parcLog_Debug(parcEventScheduler_GetLogger(parcEventSocket->eventScheduler), __VA_ARGS__)
+
+/**
+ * Current implementation based on top of libevent2
+ */
+
+#include <sys/errno.h>
+#include <event2/listener.h>
+
+/**
+ * @typedef PARCEventSocket
+ * @brief A structure containing private event state
+ */
+struct PARCEventSocket {
+ struct evconnlistener *listener;
+
+ // Event scheduler we have been queued with
+ PARCEventScheduler *eventScheduler;
+
+ // Interpose on EventSocket callbacks
+ PARCEventSocket_Callback *socketCallback;
+ void *socketUserData;
+ PARCEventSocket_ErrorCallback *socketErrorCallback;
+ void *socketErrorUserData;
+};
+
+static void
+_parc_evconn_callback(struct evconnlistener *listener, evutil_socket_t fd,
+ struct sockaddr *address, int socklen, void *ctx)
+{
+ PARCEventSocket *parcEventSocket = (PARCEventSocket *) ctx;
+ parcEventSocket_LogDebug(parcEventSocket, "_parc_evconn_callback(fd=%d,,parcEventSocket=%p)\n", fd, parcEventSocket);
+
+ parcEventSocket->socketCallback((int) fd, address, socklen, parcEventSocket->socketUserData);
+}
+
+static void
+_parc_evconn_error_callback(struct evconnlistener *listener, void *ctx)
+{
+ PARCEventSocket *parcEventSocket = (PARCEventSocket *) ctx;
+
+ int error = EVUTIL_SOCKET_ERROR();
+ char *errorString = evutil_socket_error_to_string(error);
+ parcEventSocket_LogDebug(parcEventSocket,
+ "_parc_evconn_error_callback(error=%d,errorString=%s,parcEventSocket=%p)\n",
+ error, errorString, parcEventSocket);
+
+ parcEventSocket->socketErrorCallback(parcEventSocket->eventScheduler,
+ error, errorString, parcEventSocket->socketErrorUserData);
+}
+
+PARCEventSocket *
+parcEventSocket_Create(PARCEventScheduler *eventScheduler,
+ PARCEventSocket_Callback *callback,
+ PARCEventSocket_ErrorCallback *errorCallback,
+ void *userData, const struct sockaddr *sa, int socklen)
+{
+ PARCEventSocket *parcEventSocket = parcMemory_AllocateAndClear(sizeof(PARCEventSocket));
+ assertNotNull(parcEventSocket, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCEventSocket));
+
+ parcEventSocket->eventScheduler = eventScheduler;
+ parcEventSocket->socketCallback = callback;
+ parcEventSocket->socketErrorCallback = errorCallback;
+ parcEventSocket->socketUserData = userData;
+ parcEventSocket->socketErrorUserData = userData;
+ parcEventSocket->listener = evconnlistener_new_bind(parcEventScheduler_GetEvBase(eventScheduler),
+ _parc_evconn_callback, parcEventSocket,
+ LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, -1,
+ sa, socklen);
+ if (parcEventSocket->listener == NULL) {
+ parcLog_Error(parcEventScheduler_GetLogger(eventScheduler),
+ "Libevent evconnlistener_new_bind error (%d): %s",
+ errno, strerror(errno));
+ parcEventSocket_Destroy(&parcEventSocket);
+ return NULL;
+ }
+
+ if (errorCallback) {
+ evconnlistener_set_error_cb(parcEventSocket->listener, _parc_evconn_error_callback);
+ }
+ parcEventSocket_LogDebug(parcEventSocket,
+ "parcEventSocket_Create(cb=%p,args=%p) = %p\n",
+ callback, userData, parcEventSocket);
+ return parcEventSocket;
+}
+
+void
+parcEventSocket_Destroy(PARCEventSocket **socketEvent)
+{
+ assertNotNull(*socketEvent, "parcEventSocket_Destroy must be passed a valid socketEvent!");
+
+ if ((*socketEvent)->listener) {
+ evconnlistener_free((*socketEvent)->listener);
+ }
+ parcEventSocket_LogDebug((*socketEvent), "parcEventSocket_Destroy(%p)\n", *socketEvent);
+ parcMemory_Deallocate((void **) socketEvent);
+}
+
+void
+parcEventSocket_EnableDebug(void)
+{
+ _parc_event_socket_debug_enabled = 1;
+}
+
+void
+parcEventSocket_DisableDebug(void)
+{
+ _parc_event_socket_debug_enabled = 0;
+}
diff --git a/libparc/parc/algol/parc_EventSocket.h b/libparc/parc/algol/parc_EventSocket.h
new file mode 100755
index 00000000..48a11b25
--- /dev/null
+++ b/libparc/parc/algol/parc_EventSocket.h
@@ -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.
+ */
+
+/**
+ * @file parc_EventSocket.h
+ * @ingroup events
+ * @brief Socket events
+ *
+ * Provides a facade implementing many regularly available event functions.
+ * This is an interface that software implementors may use to substitute
+ * different kinds of underlying implementations of these event management functions.
+ * Notable examples are libevent and libev.
+ *
+ */
+#ifndef libparc_parc_EventSocket_h
+#define libparc_parc_EventSocket_h
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+/**
+ * Current implementation based on top of libevent2
+ */
+
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_Event.h>
+
+typedef struct PARCEventSocket PARCEventSocket;
+
+typedef void (PARCEventSocket_Callback)(int fd, struct sockaddr *address,
+ int socklen, void *user_data);
+typedef void (PARCEventSocket_ErrorCallback)(PARCEventScheduler *,
+ int error, char *errorString,
+ void *user_data);
+
+/**
+ * Create a socket event handler instance.
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] parcEventScheduler the scheduler instance
+ * @param [in] callback the callback function.
+ * @param [in] errorCallback the error callback function.
+ * @param [in] userData pointer to private arguments for instance callback function
+ * @param [in] sa is the socket address to bind to (INET, INET6, LOCAL)
+ * @param [in] socklen is the sizeof the actual sockaddr (e.g. sizeof(sockaddr_un))
+ * @returns A pointer to a new PARCEventSocket instance.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ *
+ */
+PARCEventSocket *parcEventSocket_Create(PARCEventScheduler *parcEventScheduler,
+ PARCEventSocket_Callback *callback,
+ PARCEventSocket_ErrorCallback *errorCallback,
+ void *userData,
+ const struct sockaddr *sa, int socklen);
+
+/**
+ * Destroy a socket event handler instance.
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] parcEventSocket the address of the instance to destroy.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEvent *event = parcEventSocket_Destroy(&parcEventSocket);
+ * }
+ * @endcode
+ *
+ */
+void parcEventSocket_Destroy(PARCEventSocket **parcEventSocket);
+
+/**
+ * Turn on debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventSocket_EnableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventSocket_EnableDebug(void);
+
+/**
+ * Turn off debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventSocket_DisableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventSocket_DisableDebug(void);
+#endif // libparc_parc_EventSocket_h
diff --git a/libparc/parc/algol/parc_EventTimer.c b/libparc/parc/algol/parc_EventTimer.c
new file mode 100755
index 00000000..529188b1
--- /dev/null
+++ b/libparc/parc/algol/parc_EventTimer.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "internal_parc_Event.h"
+#include <parc/algol/parc_EventTimer.h>
+
+static int _parc_event_timer_debug_enabled = 0;
+
+#define parcEventTimer_LogDebug(parcEventTimer, ...) \
+ if (_parc_event_timer_debug_enabled) \
+ parcLog_Debug(parcEventScheduler_GetLogger(parcEventTimer->eventScheduler), __VA_ARGS__)
+
+/**
+ * Current implementation based on top of libevent2
+ */
+#include <event2/event.h>
+#include <event2/util.h>
+
+struct PARCEventTimer {
+ /**
+ * The event instance.
+ */
+ struct event *event;
+
+ // Event scheduler we have been queued with
+ PARCEventScheduler *eventScheduler;
+
+ PARCEventTimer_Callback *callback;
+ void *callbackUserData;
+};
+
+static void
+_parc_event_timer_callback(evutil_socket_t fd, short flags, void *context)
+{
+ PARCEventTimer *parcEventTimer = (PARCEventTimer *) context;
+ parcEventTimer_LogDebug(parcEventTimer,
+ "_parc_event_timer_callback(fd=%x,flags=%x,parcEventTimer=%p)\n",
+ fd, flags, parcEventTimer);
+ parcEventTimer->callback((int) fd, internal_libevent_type_to_PARCEventType(flags),
+ parcEventTimer->callbackUserData);
+}
+
+PARCEventTimer *
+parcEventTimer_Create(PARCEventScheduler *eventScheduler, PARCEventType flags, PARCEvent_Callback *callback, void *callbackArgs)
+{
+ PARCEventTimer *parcEventTimer = parcMemory_Allocate(sizeof(PARCEventTimer));
+ assertNotNull(parcEventTimer, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCEventTimer));
+
+ parcEventTimer->eventScheduler = eventScheduler;
+ parcEventTimer->callback = callback;
+ parcEventTimer->callbackUserData = callbackArgs;
+
+ // NB: the EV_TIMEOUT flag is ignored when constructing an event
+ parcEventTimer->event = event_new(parcEventScheduler_GetEvBase(eventScheduler), -1,
+ internal_PARCEventType_to_libevent_type(flags),
+ _parc_event_timer_callback, parcEventTimer);
+ assertNotNull(parcEventTimer->event, "Could not create a new event!");
+
+ parcEventTimer_LogDebug(parcEventTimer,
+ "parcEventTimer_Create(base=%p,events=%x,cb=%p,args=%p) = %p\n",
+ parcEventScheduler_GetEvBase(eventScheduler), flags,
+ callback, callbackArgs, parcEventTimer);
+
+ return parcEventTimer;
+}
+
+int
+parcEventTimer_Start(PARCEventTimer *parcEventTimer, struct timeval *timeout)
+{
+ parcEventTimer_LogDebug(parcEventTimer,
+ "parcEventTimer_Start(event=%p, timeout=%d:%d)\n",
+ parcEventTimer, timeout->tv_sec, timeout->tv_usec);
+ assertNotNull(parcEventTimer, "parcEventTimer_Start must be passed a valid event!");
+
+ int result = event_add(parcEventTimer->event, timeout);
+ return result;
+}
+
+int
+parcEventTimer_Stop(PARCEventTimer *parcEventTimer)
+{
+ parcEventTimer_LogDebug(parcEventTimer, "parcEventTimer_Stop(event=%p)\n", parcEventTimer);
+ assertNotNull(parcEventTimer, "parcEventTimer_Stop must be passed a valid event!");
+
+ int result = event_del(parcEventTimer->event);
+ return result;
+}
+
+void
+parcEventTimer_Destroy(PARCEventTimer **parcEventTimer)
+{
+ parcEventTimer_LogDebug((*parcEventTimer), "parcEventTimer_Destroy(parcEventTimer=%p)\n", *parcEventTimer);
+ assertNotNull(*parcEventTimer, "parcEventTimer_Destroy must be passed a valid parcEventTimer!");
+ assertNotNull((*parcEventTimer)->event, "parcEventTimer_Destroy passed a null event!");
+
+ event_free((*parcEventTimer)->event);
+ parcMemory_Deallocate((void **) parcEventTimer);
+}
+
+void
+parcEventTimer_EnableDebug(void)
+{
+ _parc_event_timer_debug_enabled = 1;
+}
+
+void
+parcEventTimer_DisableDebug(void)
+{
+ _parc_event_timer_debug_enabled = 0;
+}
diff --git a/libparc/parc/algol/parc_EventTimer.h b/libparc/parc/algol/parc_EventTimer.h
new file mode 100755
index 00000000..4a960853
--- /dev/null
+++ b/libparc/parc/algol/parc_EventTimer.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_EventTimer.h
+ * @ingroup events
+ * @brief Timer events
+ *
+ * Provides a facade implementing many regularly available event functions.
+ * This is an interface that software implementors may use to substitute
+ * different kinds of underlying implementations of these event management functions.
+ * Notable examples are libevent and libev.
+ *
+ */
+#ifndef libparc_parc_EventTimer_h
+#define libparc_parc_EventTimer_h
+
+#include <parc/algol/parc_Event.h>
+
+typedef void (PARCEventTimer_Callback)(int fd, PARCEventType type, void *user_data);
+
+typedef struct PARCEventTimer PARCEventTimer;
+
+/**
+ * Create a new timer event instance.
+ *
+ * The new event instance is returned.
+ *
+ * @param [in] parcEventScheduler - scheduler instance to attach to
+ * @param [in] flags - event flags
+ * @param [in] callback - timer callback function
+ * @param [in] callbackArguments - private arguments passed to callback
+ * @returns A pointer to the a PARCEventTimer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEventTimer *event = parcEvent_Create(parcEventScheduler, PARCEvent_None, callback, callbackArguments);
+ * }
+ * @endcode
+ *
+ */
+PARCEventTimer *parcEventTimer_Create(PARCEventScheduler *parcEventScheduler,
+ PARCEventType flags,
+ PARCEventTimer_Callback *callback,
+ void *callbackArguments);
+
+/**
+ * Position a timer event instance to be scheduled.
+ *
+ * @param [in] parcEventTimer - The newly created event instance and a timeout value.
+ * @param [in] timeout - time to wait for event, or NULL to wait forever.
+ * @returns -1 on error, 0 on success if nothing changed in the event backend, and 1 on success if something did.
+ *
+ * Example:
+ * @code
+ * addEvent(PARCEventTimer *parcEventTimer)
+ * {
+ * struct timeval timeout = {5, 0};
+ * int result = parcEventTimer_Start(parcEventTimer, &timeout);
+ * }
+ * @endcode
+ *
+ */
+int parcEventTimer_Start(PARCEventTimer *parcEventTimer, struct timeval *timeout);
+
+/**
+ * Stop a timer event instance.
+ *
+ * @param [in] parcEventTimer - The newly created event instance and a timeout value.
+ * @returns 0 on success
+ *
+ * Example:
+ * @code
+ * removeEvent(PARCEventTimer *parcEventTimer)
+ * {
+ * parcEventTimer_Stop(parcEventTimer);
+ * }
+ * @endcode
+ *
+ */
+int parcEventTimer_Stop(PARCEventTimer *parcEventTimer);
+
+/**
+ * Destroy an event instance.
+ *
+ * The event instance is passed in.
+ *
+ * @param [in] parcEventTimer the instance to destroy.
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventTimer_Destroy(&parcEventTimer);
+ * }
+ * @endcode
+ *
+ */
+void parcEventTimer_Destroy(PARCEventTimer **parcEventTimer);
+
+/**
+ * Turn on debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventTimer_EnableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventTimer_EnableDebug(void);
+
+/**
+ * Turn off debugging flags and messages
+ *
+ * Example:
+ * @code
+ * {
+ * parcEventTimer_DisableDebug();
+ * }
+ * @endcode
+ *
+ */
+void parcEventTimer_DisableDebug(void);
+#endif // libparc_parc_EventTimer_h
diff --git a/libparc/parc/algol/parc_Execution.c b/libparc/parc/algol/parc_Execution.c
new file mode 100644
index 00000000..8b31dcdb
--- /dev/null
+++ b/libparc/parc/algol/parc_Execution.c
@@ -0,0 +1,97 @@
+//
+// parc_Status.c
+// Libparc
+//
+//
+//
+#include <config.h>
+#include <stdio.h>
+
+#include "parc_Execution.h"
+
+/*
+ * A PARCExecution value is a unique thing which can have a string assigned to it.
+ *
+ * I want the function to be:
+ *
+ * A thing that returns an Execution
+ *
+ * Execution function() { }
+ *
+ * A thing that an Execution value can be
+ *
+ * Execution value = function;
+ */
+
+struct PARCExecution {
+ struct PARCExecution (*type)(char *format, ...);
+ char *message;
+};
+
+PARCExecution *PARCExecution_OK = &(PARCExecution) {
+ .message = "OK"
+};
+
+PARCExecution *PARCExecution_Timeout = &(PARCExecution) {
+ .message = "Timeout"
+};
+
+PARCExecution *PARCExecution_Interrupted = &(PARCExecution) {
+ .message = "Interrupted"
+};
+
+PARCExecution *PARCExecution_IOError = &(PARCExecution) {
+ .message = "I/O Error"
+};
+
+PARCExecution *
+parcExecution_OK(const char *format, ...)
+{
+ return PARCExecution_OK;
+}
+
+PARCExecution *
+parcExecution_Interrupted(const char *format, ...)
+{
+ return PARCExecution_Interrupted;
+}
+
+PARCExecution *
+parcExecution_IOError(const char *format, ...)
+{
+ return PARCExecution_IOError;
+}
+
+bool
+parcExecution_Is(const PARCExecution *exec, const PARCExecution *other)
+{
+ return (exec == other);
+}
+
+char *
+parcExecution_GetMessage(const PARCExecution *exec)
+{
+ return exec->message;
+}
+
+PARCExecution *
+bar()
+{
+ return PARCExecution_OK;
+}
+
+PARCExecution *
+baz()
+{
+ return parcExecution_OK("Nothing to say");
+}
+
+void
+foo()
+{
+ PARCExecution *x = bar();
+ PARCExecution *y = baz();
+
+ printf("%s\n", parcExecution_GetMessage(x));
+ printf("%s\n", parcExecution_GetMessage(y));
+}
diff --git a/libparc/parc/algol/parc_Execution.h b/libparc/parc/algol/parc_Execution.h
new file mode 100644
index 00000000..1aadc589
--- /dev/null
+++ b/libparc/parc/algol/parc_Execution.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 parc_Execution.h
+ * @ingroup datastructures
+ * @brief PARC Execution Status
+ * An extensible set of status values used to communicate
+ * out-of-band or exceptional conditions as return values.
+ *
+ */
+#ifndef parc_Execution_h
+#define parc_Execution_h
+
+#include <stdbool.h>
+
+struct PARCExecution;
+typedef struct PARCExecution PARCExecution;
+
+extern PARCExecution *PARCExecution_OK;
+extern PARCExecution *PARCExecution_Interrupted;
+extern PARCExecution *PARCExecution_IOError;
+extern PARCExecution *PARCExecution_Timeout;
+
+char *parcExecution_GetMessage(const PARCExecution *exec);
+
+bool parcExecution_Is(const PARCExecution *exec, const PARCExecution *other);
+
+#endif /* parc_Status_h */
diff --git a/libparc/parc/algol/parc_File.c b/libparc/parc/algol/parc_File.c
new file mode 100644
index 00000000..2ab307a2
--- /dev/null
+++ b/libparc/parc/algol/parc_File.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 500
+#endif //_XOPEN_SOURCE 500
+
+#ifndef __USE_XOPEN_EXTENDED
+#define __USE_XOPEN_EXTENDED
+#endif //__USE_XOPEN_EXTENDED
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+
+#include <ftw.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <string.h>
+#include <errno.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_PathName.h>
+#include <parc/algol/parc_File.h>
+#include <parc/algol/parc_Memory.h>
+
+
+struct parc_file {
+ PARCPathName *pathName;
+};
+
+static bool
+_parcFile_Destructor(PARCFile **filePtr)
+{
+ PARCFile *file = *filePtr;
+
+ parcPathName_Release(&file->pathName);
+
+ return true;
+}
+
+parcObject_Override(PARCFile, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcFile_Destructor,
+ .toString = (PARCObjectToString *) parcFile_ToString);
+
+void
+parcFile_AssertValid(const PARCFile *instance)
+{
+ trapIllegalValueIf(instance == NULL, "Parameter must be a non-null pointer to a valid PARCFile.");
+ trapIllegalValueIf(instance->pathName == NULL, "PARCFile cannot have a NULL path-name");
+}
+
+PARCFile *
+parcFile_Create(const char *path)
+{
+ PARCFile *result = NULL;
+
+ PARCPathName *pathName = parcPathName_Parse(path);
+ if (pathName != NULL) {
+ result = parcObject_CreateInstance(PARCFile);
+ if (result != NULL) {
+ result->pathName = pathName;
+ } else {
+ parcPathName_Release(&pathName);
+ }
+ }
+
+ return result;
+}
+
+PARCFile *
+parcFile_CreateChild(const PARCFile *parent, char *fileName)
+{
+ PARCFile *result = NULL;
+
+ PARCPathName *childPath = parcPathName_Append(parcPathName_Copy(parent->pathName), fileName);
+
+ if (childPath != NULL) {
+ result = parcObject_CreateInstance(PARCFile);
+ if (result != NULL) {
+ result->pathName = childPath;
+ }
+ }
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcFile, PARCFile);
+
+parcObject_ImplementRelease(parcFile, PARCFile);
+
+bool
+parcFile_CreateNewFile(const PARCFile *file)
+{
+ parcFile_OptionalAssertValid(file);
+
+ bool result = false;
+
+ char *string = parcPathName_ToString(file->pathName);
+
+ int fd = open(string, O_EXCL | O_CREAT | O_TRUNC, 0666);
+ if (fd != -1) {
+ close(fd);
+ result = true;
+ }
+ parcMemory_Deallocate((void **) &string);
+
+ return result;
+}
+
+bool
+parcFile_Mkdir(const PARCFile *file)
+{
+ parcFile_OptionalAssertValid(file);
+
+ char *string = parcPathName_ToString(file->pathName);
+ bool result = (mkdir(string, 0777) == 0);
+ parcMemory_Deallocate((void **) &string);
+
+ return result;
+}
+
+bool
+parcFile_Exists(const PARCFile *file)
+{
+ struct stat statbuf;
+
+ char *string = parcPathName_ToString(file->pathName);
+ bool result = stat(string, &statbuf) == 0;
+ parcMemory_Deallocate((void **) &string);
+
+ return result;
+}
+
+bool
+parcFile_IsDirectory(const PARCFile *file)
+{
+ bool result = false;
+ struct stat statbuf;
+
+ char *string = parcPathName_ToString(file->pathName);
+ if (stat(string, &statbuf) == 0) {
+ result = S_ISDIR(statbuf.st_mode);
+ }
+ parcMemory_Deallocate((void **) &string);
+
+ return result;
+}
+
+static int
+_deleteNode(const char *path, const struct stat *stat, int flag, struct FTW *ftwbuf)
+{
+ int result = 0;
+
+ if (flag == FTW_DP) { // directory in post-order
+ result = rmdir(path);
+ } else {
+ result = unlink(path);
+ }
+ return result;
+}
+
+/**
+ * @function parcFile_Delete
+ * @abstract Deletes the file or directory
+ * @discussion
+ *
+ * @param <#param1#>
+ * @return true if everything deleted, false otherwise
+ */
+bool
+parcFile_Delete(const PARCFile *file)
+{
+ char *string = parcPathName_ToString(file->pathName);
+
+ // only allow under tmp
+ assertTrue(strncmp(string, "/tmp/", 5) == 0,
+ "Path must begin with /tmp/: %s", string);
+ // dont allow ".."
+ assertNull(strstr(string, ".."), "Path cannot have .. in it: %s", string);
+
+ bool result = false;
+ if (parcFile_IsDirectory(file)) {
+ // depth first, dont't follow symlinks, do not cross mount points.
+ int flags = FTW_DEPTH | FTW_PHYS | FTW_MOUNT;
+
+ // maximum 20 fds open at a time
+ int maximumFileDescriptors = 20;
+
+ int failure = nftw(string, _deleteNode, maximumFileDescriptors, flags);
+ assertFalse(failure, "Error on recursive delete: (%d) %s", errno, strerror(errno));
+
+ result = failure == false;
+ } else {
+ result = (unlink(string) == 0);
+ }
+
+ parcMemory_Deallocate((void **) &string);
+
+ return result;
+}
+
+PARCBufferComposer *
+parcFile_BuildString(const PARCFile *file, PARCBufferComposer *composer)
+{
+ parcPathName_BuildString(file->pathName, composer);
+
+ return composer;
+}
+
+char *
+parcFile_ToString(const PARCFile *file)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcFile_BuildString(file, composer);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+size_t
+parcFile_GetFileSize(const PARCFile *file)
+{
+ size_t fileSize = 0;
+
+ char *fname = parcPathName_ToString(file->pathName);
+
+ struct stat st;
+
+ if (stat(fname, &st) == 0) {
+ fileSize = st.st_size;
+ }
+
+ parcMemory_Deallocate(&fname);
+
+ return fileSize;
+}
diff --git a/libparc/parc/algol/parc_File.h b/libparc/parc/algol/parc_File.h
new file mode 100755
index 00000000..42ef232e
--- /dev/null
+++ b/libparc/parc/algol/parc_File.h
@@ -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.
+ */
+
+/**
+ * @file parc_File.h
+ * @ingroup inputoutput
+ * @brief File manipulation
+ *
+ *
+ */
+#ifndef libparc_parc_File_h
+#define libparc_parc_File_h
+
+#include <stdbool.h>
+
+#include <parc/algol/parc_BufferComposer.h>
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcFile_OptionalAssertValid(_instance_)
+#else
+# define parcFile_OptionalAssertValid(_instance_) parcFile_AssertValid(_instance_)
+#endif
+
+struct parc_file;
+typedef struct parc_file PARCFile;
+
+/**
+ * Creates a `PARCFile` object named by pathname.
+ *
+ * This operation does not imply any I/O operations.
+ * The PARCFile instance only represents the pathname,
+ * and does not necessarily reference a real file.
+ *
+ * @param [in] pathname is a pointer to a char array (string)
+ * @return A pointer to an instance of `PARCFile`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCFile *parcFile_Create(const char *pathname);
+
+/**
+ * Acquire a new reference to an instance of `PARCFile`.
+ *
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] file The instance of `PARCFile` to which to refer.
+ *
+ * @return The same value as the input parameter @p file
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFile *parcFile_Acquire(const PARCFile *file);
+
+/**
+ * Assert that an instance of `PARCFile` 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 `PARCFile` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFile *file = parcFile_Create("/tmp/foo");
+ *
+ * parcFile_AssertValid(file);
+ * }
+ * @endcode
+ */
+void parcFile_AssertValid(const PARCFile *instance);
+
+/**
+ * Release a `PARCFile` reference.
+ *
+ * Only the last invocation where the reference count is decremented to zero,
+ * will actually destroy the `PARCFile`.
+ *
+ * @param [in,out] filePtr is a pointer to the `PARCFile` reference.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcFile_Release(PARCFile **filePtr);
+
+/**
+ * Create a new file on storage.
+ *
+ * @param [in] file A pointer to an instance of `PARCFile`
+ *
+ * @return true if succesful, false if not
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcFile_CreateNewFile(const PARCFile *file);
+
+/**
+ * Return true if the PARCFile exists on storage.
+ *
+ * If the pathname can be stat(2)'d, then it exists.
+ *
+ * @param [in] file A pointer to a `PARCFile` instance.
+ * @return true if the file exists, false otherwise
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcFile_Exists(const PARCFile *file);
+
+/**
+ * Create a new directory.
+ *
+ * @param [in] file A pointer to a `PARCFile` instance.
+ * @return true if the pathname exists, false otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcFile_Mkdir(const PARCFile *file);
+
+/**
+ * True if the specified `PARCFile` is an existing directory on storage.
+ *
+ * @param [in] file A pointer to a `PARCFile` instance.
+ *
+ * @return true if specified `PARCFile` is an existing directory on storage, false if not
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcFile_IsDirectory(const PARCFile *file);
+
+/**
+ * Deletes the file or directory on storage.
+ *
+ * For a directory, it does a recursive delete.
+ *
+ * @param [in] file The instance of `PARCFile` to be deleted.
+ * @return `true` if everything deleted, false otherwise
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcFile_Delete(const PARCFile *file);
+
+/**
+ * Append a representation of the specified `PARCFile` instance to the given {@link PARCBufferComposer}.
+ *
+ * @param [in] file A pointer to the `PARCFile` instance whose contents should be appended to to string.
+ * @param [in,out] string A pointer to the `PARCBufferComposer` instance to which the contents of file will be appended.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The instance of `PARCBufferComposer` with the appended contents.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ * PARCFile *instance = parcFile_Create("/tmp/foo");
+ *
+ * parcFile_BuildString(instance, result);
+ *
+ * PARCBuffer *string = parcBufferComposer_FinalizeBuffer(result);
+ * printf("File: %s\n", parcBuffer_ToString(string));
+ * parcBuffer_Release(&string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcFile_BuildString(const PARCFile *file, PARCBufferComposer *string);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+size_t parcFile_GetFileSize(const PARCFile *file);
+
+/**
+ * Create a PARCFile representation of the home directory of the current user.
+ *
+ * The return value must be released via `parcFile_Release`.
+ *
+ * @return non-NULL A pointer to a valid PARCFile instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFile *directory = parcFile_CreateHome();
+ * }
+ * @endcode
+ */
+PARCFile *parcFile_CreateHome(void);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCFile` instance.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] file A pointer to the `PARCFile` 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
+ * {
+ * PARCFile *instance = parcFile_Create("/tmp/foo");
+ *
+ * char *string = parcFile_ToString(instance);
+ *
+ * if (string != NULL) {
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * parcFile_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see {@link parcFile_BuildString}
+ */
+char *parcFile_ToString(const PARCFile *file);
+#endif // libparc_parc_File_h
diff --git a/libparc/parc/algol/parc_FileChunker.c b/libparc/parc/algol/parc_FileChunker.c
new file mode 100644
index 00000000..d7acd58e
--- /dev/null
+++ b/libparc/parc/algol/parc_FileChunker.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <sys/time.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_RandomAccessFile.h>
+
+#include <parc/algol/parc_FileChunker.h>
+
+PARCChunkerInterface *PARCFileChunkerAsChunker = &(PARCChunkerInterface) {
+ .ForwardIterator = (void *(*)(const void *))parcFileChunker_ForwardIterator,
+ .ReverseIterator = (void *(*)(const void *))parcFileChunker_ReverseIterator,
+ .GetChunkSize = (size_t (*)(const void *))parcFileChunker_GetChunkSize
+};
+
+struct _parc_chunker_state {
+ size_t chunkNumber;
+ int direction;
+ bool atEnd;
+ size_t position;
+ size_t nextChunkSize;
+ size_t totalSize;
+};
+
+typedef struct _parc_chunker_state _ChunkerState;
+
+struct parc_buffer_chunker {
+ // State
+ size_t chunkSize;
+
+ // Container for the data to be parsed
+ PARCFile *file;
+ PARCRandomAccessFile *fhandle;
+
+ // The current element of the iterator
+ PARCBuffer *currentElement;
+};
+
+static void
+_destroy(PARCFileChunker **chunkerP)
+{
+ if ((*chunkerP)->fhandle != NULL) {
+ parcRandomAccessFile_Release(&(*chunkerP)->fhandle);
+ }
+
+ if ((*chunkerP)->file != NULL) {
+ parcFile_Release(&(*chunkerP)->file);
+ }
+
+ if ((*chunkerP)->currentElement != NULL) {
+ parcBuffer_Release(&(*chunkerP)->currentElement);
+ }
+}
+
+static void *
+_InitForward(PARCFileChunker *chunker)
+{
+ _ChunkerState *state = parcMemory_Allocate(sizeof(_ChunkerState));
+
+ state->chunkNumber = 0;
+ state->direction = 0;
+ state->position = 0;
+ state->atEnd = false;
+ state->totalSize = parcFile_GetFileSize(chunker->file);
+
+ if (state->totalSize < chunker->chunkSize) {
+ state->position = 0;
+ state->nextChunkSize = state->totalSize;
+ } else {
+ state->position = 0;
+ state->nextChunkSize = chunker->chunkSize;
+ }
+
+ return state;
+}
+
+static void *
+_InitReverse(PARCFileChunker *chunker)
+{
+ _ChunkerState *state = parcMemory_Allocate(sizeof(_ChunkerState));
+
+ state->chunkNumber = 0;
+ state->direction = 1;
+ state->atEnd = false;
+ state->totalSize = parcFile_GetFileSize(chunker->file);
+
+ if (state->totalSize < chunker->chunkSize) {
+ state->position = 0;
+ state->nextChunkSize = state->totalSize;
+ } else {
+ state->position = state->totalSize - chunker->chunkSize;
+ state->nextChunkSize = chunker->chunkSize;
+ }
+
+ return state;
+}
+
+static bool
+_parcChunker_HasNext(PARCFileChunker *chunker, void *voidstate)
+{
+ _ChunkerState *state = (_ChunkerState *) voidstate;
+ return !state->atEnd;
+}
+
+static void
+_advanceStateForward(PARCFileChunker *chunker, _ChunkerState *state)
+{
+ state->position += state->nextChunkSize;
+ size_t remaining = state->totalSize - state->position;
+
+ if (remaining == 0) {
+ state->atEnd = true;
+ } else if (remaining > chunker->chunkSize) {
+ state->nextChunkSize = chunker->chunkSize;
+ } else {
+ state->nextChunkSize = remaining;
+ }
+}
+
+static void
+_advanceStateBackward(PARCFileChunker *chunker, _ChunkerState *state)
+{
+ // Previous chunk size
+ size_t chunkSize = state->nextChunkSize;
+ if (chunkSize != chunker->chunkSize || state->position == 0) {
+ state->atEnd = true;
+ } else {
+ if (state->position < chunkSize) {
+ state->nextChunkSize = state->position; // on next read, go to the current position
+ state->position = 0; // we reached the beginning
+ } else {
+ state->position -= chunkSize;
+ }
+ }
+}
+
+static void
+_advanceState(PARCFileChunker *chunker, _ChunkerState *state)
+{
+ state->chunkNumber++;
+
+ if (state->direction == 0) {
+ _advanceStateForward(chunker, state);
+ } else {
+ _advanceStateBackward(chunker, state);
+ }
+}
+
+static void *
+_parcChunker_NextFromBuffer(PARCFileChunker *chunker, _ChunkerState *state)
+{
+ size_t chunkSize = state->nextChunkSize;
+
+ parcRandomAccessFile_Seek(chunker->fhandle, state->position, PARCRandomAccessFilePosition_Start);
+
+ PARCBuffer *slice = parcBuffer_Allocate(chunkSize);
+ parcRandomAccessFile_Read(chunker->fhandle, slice);
+ slice = parcBuffer_Flip(slice);
+
+ _advanceState(chunker, state);
+
+ return slice;
+}
+
+static void *
+_parcChunker_Next(PARCFileChunker *chunker, void *state)
+{
+ PARCBuffer *buffer = _parcChunker_NextFromBuffer(chunker, state);
+
+ if (chunker->currentElement != NULL) {
+ parcBuffer_Release(&chunker->currentElement);
+ }
+ if (buffer != NULL) {
+ chunker->currentElement = parcBuffer_Acquire(buffer);
+ }
+
+ return state;
+}
+
+static void
+_parcChunker_RemoveAt(PARCFileChunker *chunker, void **state)
+{
+ // pass
+}
+
+static void *
+_parcChunker_GetElement(PARCFileChunker *chunker, void *state)
+{
+ return chunker->currentElement;
+}
+
+static void
+_parcChunker_Finish(PARCFileChunker *chunker, void *state)
+{
+ _ChunkerState *thestate = (_ChunkerState *) state;
+ parcMemory_Deallocate(&thestate);
+}
+
+static void
+_parcChunker_AssertValid(const void *state)
+{
+ // pass
+}
+
+parcObject_ExtendPARCObject(PARCFileChunker, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+parcObject_ImplementAcquire(parcFileChunker, PARCFileChunker);
+parcObject_ImplementRelease(parcFileChunker, PARCFileChunker);
+
+PARCFileChunker *
+parcFileChunker_Create(PARCFile *file, size_t chunkSize)
+{
+ PARCFileChunker *chunker = parcObject_CreateInstance(PARCFileChunker);
+
+ if (chunker != NULL) {
+ chunker->chunkSize = chunkSize;
+ chunker->file = parcFile_Acquire(file);
+ chunker->fhandle = parcRandomAccessFile_Open(chunker->file);
+ chunker->currentElement = NULL;
+ }
+
+ return chunker;
+}
+
+
+PARCIterator *
+parcFileChunker_ForwardIterator(const PARCFileChunker *chunker)
+{
+ PARCIterator *iterator = parcIterator_Create((void *) chunker,
+ (void *(*)(PARCObject *))_InitForward,
+ (bool (*)(PARCObject *, void *))_parcChunker_HasNext,
+ (void *(*)(PARCObject *, void *))_parcChunker_Next,
+ (void (*)(PARCObject *, void **))_parcChunker_RemoveAt,
+ (void *(*)(PARCObject *, void *))_parcChunker_GetElement,
+ (void (*)(PARCObject *, void *))_parcChunker_Finish,
+ (void (*)(const void *))_parcChunker_AssertValid);
+
+ return iterator;
+}
+
+PARCIterator *
+parcFileChunker_ReverseIterator(const PARCFileChunker *chunker)
+{
+ PARCIterator *iterator = parcIterator_Create((void *) chunker,
+ (void *(*)(PARCObject *))_InitReverse,
+ (bool (*)(PARCObject *, void *))_parcChunker_HasNext,
+ (void *(*)(PARCObject *, void *))_parcChunker_Next,
+ (void (*)(PARCObject *, void **))_parcChunker_RemoveAt,
+ (void *(*)(PARCObject *, void *))_parcChunker_GetElement,
+ (void (*)(PARCObject *, void *))_parcChunker_Finish,
+ (void (*)(const void *))_parcChunker_AssertValid);
+
+ return iterator;
+}
+
+size_t
+parcFileChunker_GetChunkSize(const PARCFileChunker *chunker)
+{
+ return chunker->chunkSize;
+}
diff --git a/libparc/parc/algol/parc_FileChunker.h b/libparc/parc/algol/parc_FileChunker.h
new file mode 100755
index 00000000..6ab0d267
--- /dev/null
+++ b/libparc/parc/algol/parc_FileChunker.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 parc_FileChunker.h
+ * @ingroup ContentObject
+ * @brief A FileChunker is a chunker that segments the content of a file.
+ *
+ */
+
+#ifndef libparc_parc_FileChunker_h
+#define libparc_parc_FileChunker_h
+
+#include <parc/algol/parc_Chunker.h>
+
+#include <parc/algol/parc_File.h>
+
+struct parc_buffer_chunker;
+/**
+ * @typedef PARCFileChunker
+ * @brief The PARC Chunker
+ */
+typedef struct parc_buffer_chunker PARCFileChunker;
+
+/**
+ * The mapping of a `PARCFileChunker` to the generic `PARCChunker`.
+ */
+extern PARCChunkerInterface *PARCFileChunkerAsChunker;
+
+/**
+ * Create a new chunker to segment data contained in a `PARCBuffer.`
+ *
+ * @param [in] file A `PARCFile` from which the data will be read.
+ * @param [in] chunkSize The size per chunk.
+ *
+ * @retval PARCFileChunker A newly allocated `PARCFileChunker`
+ * @retval NULL An error occurred.
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCFileChunker *chunker = PARCFileChunker_CreateFromBuffer(dataToChunk, 32);
+ * }
+ */
+PARCFileChunker *parcFileChunker_Create(PARCFile *file, size_t chunkSize);
+
+/**
+ * Increase the number of references to a `PARCFileChunker` instance.
+ *
+ * Note that new `PARCFileChunker` is not created,
+ * only that the given `PARCFileChunker` reference count is incremented.
+ * Discard the reference by invoking {@link PARCFileChunker_Release}.
+ *
+ * @param [in] chunker A pointer to the original `PARCFileChunker`.
+ * @return The value of the input parameter @p chunker.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileChunker *original = parcFileChunker_Create(...);
+ *
+ * PARCFileChunker *reference = parcFileChunker_Acquire(original);
+ *
+ * parcFileChunker_Release(&original);
+ * parcFileChunker_Release(&reference);
+ * }
+ * @endcode
+ *
+ * @see parcFileChunker_Release
+ */
+PARCFileChunker *parcFileChunker_Acquire(const PARCFileChunker *chunker);
+
+/**
+ * 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] chunkerP A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCFileChunker *chunker = parcFileChunker_Acquire(instance);
+ *
+ * parcFileChunker_Release(&chunker);
+ * }
+ * @endcode
+ */
+void parcFileChunker_Release(PARCFileChunker **chunkerP);
+
+/**
+ * Determine if two `PARCFileChunker` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCFileChunker` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcFileChunker_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcFileChunker_Equals(x, y)` must return true if and only if
+ * `parcFileChunker_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcFileChunker_Equals(x, y)` returns true and
+ * `parcFileChunker_Equals(y, z)` returns true,
+ * then `parcFileChunker_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcFileChunker_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcFileChunker_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param chunkerA A pointer to a `PARCFileChunker` instance.
+ * @param chunkerB A pointer to a `PARCFileChunker` instance.
+ * @return true if the two `PARCFileChunker` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * char *fileToChunk = ...
+ * PARCFileChunker *chunkerA = parcFileChunker_Create(fileToChunk, 32);
+ * PARCFileChunker *chunkerB = parcFileChunker_Create(fileToChunk, 32);
+ *
+ * bool equals = parcFileChunker_Equals(chunkerA, chunkerB);
+ * }
+ * @endcode
+ */
+bool parcFileChunker_Equals(const PARCFileChunker *chunkerA, const PARCFileChunker *chunkerB);
+
+/**
+ * Return an iterator to traverse the chunks of the underlying data in sequential order.
+ *
+ * This function can only be called once per chunker instance since the iterator
+ * will mutate internal state of the chunker.
+ *
+ * @param [in] chunker A `PARCFileChunker` instance.
+ *
+ * @return a `PARCIterator` that traverses the chunks of the underlying data.
+ *
+ * Example
+ * @code
+ * {
+ * char *fileToChunk = ...
+ * PARCFileChunker *chunker = parcFileChunker_Create(fileToChunk, 32);
+ *
+ * PARCIterator *itr = parcFileChunker_ForwardIterator(chunker);
+ *
+ * // use the iterator to traverse the chunker
+ * }
+ * @endcode
+ */
+PARCIterator *parcFileChunker_ForwardIterator(const PARCFileChunker *chunker);
+
+/**
+ * Return an iterator to traverse the chunks of the underlying data in sequential order.
+ *
+ * This function can only be called once per chunker instance since the iterator
+ * will mutate internal state of the chunker.
+ *
+ * @param [in] chunker A `PARCFileChunker` instance.
+ *
+ * @return a `PARCIterator` that traverses the chunks of the underlying data.
+ *
+ * Example
+ * @code
+ * {
+ * char *fileToChunk = ...
+ * PARCFileChunker *chunker = parcFileChunker_Create(fileToChunk, 32);
+ *
+ * PARCIterator *itr = parcFileChunker_ReverseIterator(chunker);
+ *
+ * // use the iterator to traverse the chunker
+ * }
+ * @endcode
+ */
+PARCIterator *parcFileChunker_ReverseIterator(const PARCFileChunker *chunker);
+
+/**
+ * Get the chunk size of a `PARCFileChunker.`
+ *
+ * @param [in] chunker A `PARCFileChunker` instance.
+ *
+ * @return the chunk size
+ *
+ * Example
+ * @code
+ * {
+ * PARCBuffer *dataToChunk = ...
+ * PARCFileChunker *chunker = ...
+ *
+ * size_t chunkSize = parcFileChunker_GetChunkSize(chunker);
+ * }
+ * @endcode
+ */
+size_t parcFileChunker_GetChunkSize(const PARCFileChunker *chunker);
+#endif // libparc_parc_FileChunker_h
diff --git a/libparc/parc/algol/parc_FileInputStream.c b/libparc/parc/algol/parc_FileInputStream.c
new file mode 100755
index 00000000..f42ced73
--- /dev/null
+++ b/libparc/parc/algol/parc_FileInputStream.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 <config.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_File.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_InputStream.h>
+#include <parc/algol/parc_FileInputStream.h>
+#include <parc/algol/parc_Object.h>
+
+PARCInputStreamInterface *PARCFileInputStreamAsPARCInputStream = &(PARCInputStreamInterface) {
+ .Acquire = (PARCInputStream * (*)(const PARCInputStream *))parcFileInputStream_Acquire,
+ .Release = (void (*)(PARCInputStream **))parcFileInputStream_Release,
+ .Read = (size_t (*)(PARCInputStream *, PARCBuffer *))parcFileInputStream_Read
+};
+
+struct parc_file_input_stream {
+ int fd;
+};
+
+static void
+_destroy(PARCFileInputStream **inputStreamPtr)
+{
+ PARCFileInputStream *inputStream = *inputStreamPtr;
+
+ close(inputStream->fd);
+}
+
+parcObject_ExtendPARCObject(PARCFileInputStream, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCFileInputStream *
+parcFileInputStream_Open(const PARCFile *file)
+{
+ PARCFileInputStream *result = NULL;
+
+ char *fileName = parcFile_ToString(file);
+ if (fileName != NULL) {
+ result = parcFileInputStream_Create(open(fileName, O_RDONLY));
+ parcMemory_Deallocate((void **) &fileName);
+ }
+
+ return result;
+}
+
+PARCFileInputStream *
+parcFileInputStream_Create(int fileDescriptor)
+{
+ trapIllegalValueIf(fileDescriptor < 0, "File descriptor must not be negative.");
+
+ PARCFileInputStream *result = parcObject_CreateInstance(PARCFileInputStream);
+ if (result != NULL) {
+ result->fd = fileDescriptor;
+ }
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcFileInputStream, PARCFileInputStream);
+parcObject_ImplementRelease(parcFileInputStream, PARCFileInputStream);
+
+bool
+parcFileInputStream_Read(PARCFileInputStream *inputStream, PARCBuffer *buffer)
+{
+ while (parcBuffer_HasRemaining(buffer)) {
+ void *buf = parcBuffer_Overlay(buffer, 0);
+ ssize_t nread = read(inputStream->fd, buf, parcBuffer_Remaining(buffer));
+ if (nread < 0) {
+ break;
+ }
+ parcBuffer_SetPosition(buffer, parcBuffer_Position(buffer) + nread);
+ }
+ return parcBuffer_HasRemaining(buffer);
+}
+
+PARCBuffer *
+parcFileInputStream_ReadFile(PARCFileInputStream *inputStream)
+{
+ PARCBuffer *result = NULL;
+
+ struct stat statbuf;
+
+ if (fstat(inputStream->fd, &statbuf) == 0) {
+ result = parcBuffer_Allocate(statbuf.st_size);
+ if (result != NULL) {
+ parcFileInputStream_Read(inputStream, result);
+ }
+ }
+
+ return result;
+}
diff --git a/libparc/parc/algol/parc_FileInputStream.h b/libparc/parc/algol/parc_FileInputStream.h
new file mode 100755
index 00000000..3641e08a
--- /dev/null
+++ b/libparc/parc/algol/parc_FileInputStream.h
@@ -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.
+ */
+
+/**
+ * @file parc_FileInputStream.h
+ * @ingroup inputoutput
+ * @brief A FileInputStream obtains input bytes from a file in a file system.
+ *
+ * What files are available depends on the host environment.
+ * FileInputStream is meant for reading streams of raw bytes such as image data.
+ *
+ */
+
+#ifndef libparc_parc_FileInputStream_h
+#define libparc_parc_FileInputStream_h
+
+#include <parc/algol/parc_File.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_InputStream.h>
+
+struct parc_file_input_stream;
+
+/**
+ * @typedef PARCFileInputStream
+ * @brief Read streams of input
+ */
+
+typedef struct parc_file_input_stream PARCFileInputStream;
+
+/**
+ * The mapping of a `PARCFileInputStream` to the generic `PARCInputStream`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCInputStreamInterface *PARCFileInputStreamAsPARCInputStream;
+
+/**
+ * Create a `PARCFileInputStream` instance.
+ *
+ * @param [in] fileDescriptor An abstract indicator for accessing a specific file
+ *
+ * @return non-NULL A pointer to an instance of `PARCFileInputStream`
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFileInputStream *parcFileInputStream_Create(int fileDescriptor);
+
+/**
+ * Create a `PARCFileInputStream` instance by opening an existing {@link PARCFile} instance.
+ *
+ * The file specified by `PARCFile` must exist and readable.
+ *
+ * @param [in] file A pointer to a `PARCFile` instance representing the existing file.
+ *
+ * @return non-NULL A pointer to a `PARCFileInputStream` instance.
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFileInputStream *parcFileInputStream_Open(const PARCFile *file);
+
+/**
+ * Acquire a new reference to an instance of `PARCFileInputStream`.
+ *
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] inputStream The instance of `PARCFileInputStream` to which to refer.
+ *
+ * @return The same value as the input parameter @p inputStream
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFileInputStream *parcFileInputStream_Acquire(const PARCFileInputStream *inputStream);
+
+/**
+ * Release a `PARCFileInputStream` reference.
+ *
+ * Only the last invocation where the reference count is decremented to zero,
+ * will actually destroy the `PARCFileInputStream`.
+ *
+ * @param [in,out] inputStreamPtr is a pointer to the `PARCFileInputStream` reference.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+void parcFileInputStream_Release(PARCFileInputStream **inputStreamPtr);
+
+/**
+ * Read a `PARCFileInputStream` into a {@link PARCBuffer}.
+ *
+ * The contents of the `PARCBuffer` are filled from the current position to the limit.
+ * When this function returns, the position is set to the end of the last successfully read byte of data.
+ *
+ * @param [in] inputStream The `PARCInputStream` to read.
+ * @param [in] buffer The `PARCBuffer` to read, from the current position of the buffer to its limit.
+ *
+ * @return true The entire contents of the `PARCBuffer`, from the current position to the limit, were filled.
+ * @return false The entire contents of the `PARCBuffer` were not filled.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *stream =
+ * parcFileOutputStream_Create(open("/tmp/test_parc_FileOutputStream", O_CREAT|O_WRONLY|O_TRUNC, 0600));
+ *
+ * PARCBuffer *buffer = parcBuffer_Allocate(16 * 1024*1024);
+ *
+ * parcFileOutputStream_Write(stream, buffer);
+ *
+ * assertFalse(parcBuffer_HasRemaining(buffer), "Expected the buffer to be emtpy");
+ *
+ * parcBuffer_Release(&buffer);
+ *
+ * parcFileOutputStream_Release(&stream);
+ * }
+ * @endcode
+ *
+ */
+bool parcFileInputStream_Read(PARCFileInputStream *inputStream, PARCBuffer *buffer);
+
+/**
+ * Read the content of a `PARCFileInputStream` into a {@link PARCBuffer}.
+ *
+ * @param [in] inputStream The `PARCFileInputStream` to read.
+ *
+ * @return non-NULL A pointer to a `PARCBuffer` instance containing the content of the `PARCFileInputStream`.
+ * @return NULl Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCBuffer *parcFileInputStream_ReadFile(PARCFileInputStream *inputStream);
+#endif // libparc_parc_FileInputStream_h
diff --git a/libparc/parc/algol/parc_FileOutputStream.c b/libparc/parc/algol/parc_FileOutputStream.c
new file mode 100755
index 00000000..a17dc66c
--- /dev/null
+++ b/libparc/parc/algol/parc_FileOutputStream.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 <unistd.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/algol/parc_Object.h>
+
+PARCOutputStreamInterface *PARCFileOutputStreamAsPARCInputStream = &(PARCOutputStreamInterface) {
+ .Acquire = (PARCOutputStream * (*)(PARCOutputStream *))parcFileOutputStream_Acquire,
+ .Release = (void (*)(PARCOutputStream **))parcFileOutputStream_Release,
+ .Write = (size_t (*)(PARCOutputStream *, PARCBuffer *))parcFileOutputStream_Write
+};
+
+struct parc_file_output_stream {
+ int fd;
+};
+
+static void
+_destroy(PARCFileOutputStream **streamPtr)
+{
+ PARCFileOutputStream *stream = *streamPtr;
+
+ close(stream->fd);
+}
+
+parcObject_ExtendPARCObject(PARCFileOutputStream, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCFileOutputStream *
+parcFileOutputStream_Create(int fileDescriptor)
+{
+ assertTrue(fileDescriptor != -1, "Invalid file descriptor");
+
+ PARCFileOutputStream *result = parcObject_CreateInstance(PARCFileOutputStream);
+ result->fd = fileDescriptor;
+
+ return result;
+}
+
+PARCOutputStream *
+parcFileOutputStream_AsOutputStream(PARCFileOutputStream *fileOutputStream)
+{
+ return parcOutputStream_Create(parcFileOutputStream_Acquire(fileOutputStream), PARCFileOutputStreamAsPARCInputStream);
+}
+
+parcObject_ImplementAcquire(parcFileOutputStream, PARCFileOutputStream);
+
+parcObject_ImplementRelease(parcFileOutputStream, PARCFileOutputStream);
+
+bool
+parcFileOutputStream_Write(PARCFileOutputStream *outputStream, PARCBuffer *buffer)
+{
+ const size_t maximumChunkSize = 1024 * 1024;
+
+ while (parcBuffer_HasRemaining(buffer)) {
+ size_t remaining = parcBuffer_Remaining(buffer);
+ size_t chunkSize = remaining > maximumChunkSize ? maximumChunkSize : remaining;
+ void *buf = parcBuffer_Overlay(buffer, chunkSize);
+ ssize_t nwritten = write(outputStream->fd, buf, chunkSize);
+ if (nwritten == -1) {
+ break;
+ }
+ }
+
+ return parcBuffer_HasRemaining(buffer) == false;
+}
diff --git a/libparc/parc/algol/parc_FileOutputStream.h b/libparc/parc/algol/parc_FileOutputStream.h
new file mode 100644
index 00000000..51251561
--- /dev/null
+++ b/libparc/parc/algol/parc_FileOutputStream.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_FileOutputStream.h
+ * @ingroup inputoutput
+ * @brief A file output stream is an output stream for writing data to a File or to a FileDescriptor.
+ *
+ * Whether or not a file is available or may be created depends upon the underlying platform.
+ * Some platforms, in particular, allow a file to be opened for writing by only one FileOutputStream
+ * (or other file-writing object) at a time. In such situations the constructors in this class will
+ * fail if the file involved is already open.
+ *
+ */
+
+#ifndef libparc_parc_FileOutputStream_h
+#define libparc_parc_FileOutputStream_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_OutputStream.h>
+
+struct parc_file_output_stream;
+typedef struct parc_file_output_stream PARCFileOutputStream;
+
+/**
+ * The mapping of a `PARCFileOutputStream` to the generic `PARCInputStream`.
+ *
+ */
+extern PARCOutputStreamInterface *PARCFileOutputStreamAsPARCOutputStream;
+
+/**
+ * Create a new output stream on a file descriptor.
+ *
+ * Caution: When the resulting `PARCFileOutputStream` is released, the file descriptor is closed.
+ * If you wrap STDOUT_FILENO, for example, the standard output of the application will be closed
+ * when this PARCFileOutputStream is released.
+ * To avoid this, use dup(2) or dup2(2).
+ *
+ * @param [in] fileDescriptor The fileDescriptor for the file on which to create an output stream.
+ *
+ * @return A pointer to a new instance of `PARCFileOutputStream`
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFileOutputStream *parcFileOutputStream_Create(int fileDescriptor);
+
+/**
+ * Convert an instance of `PARCFileOutputStream` to a `PARCOutputStream`.
+ *
+ * @param [in] fileOutputStream A pointer to a valid PARCFileOutputStream.
+ *
+ * @return A pointer to a new instance of `PARCOutputStream`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCOutputStream *parcFileOutputStream_AsOutputStream(PARCFileOutputStream *fileOutputStream);
+
+/**
+ * Acquire a new reference to an instance of `PARCFileOutputStream`.
+ *
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] stream The instance of `PARCFileOutputStream` to which to refer.
+ *
+ * @return The same value as the input parameter @p stream
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFileOutputStream *parcFileOutputStream_Acquire(const PARCFileOutputStream *stream);
+
+/**
+ * Release a `PARCFileOutputStream` reference.
+ *
+ * Only the last invocation where the reference count is decremented to zero,
+ * will actually destroy the `PARCFileOutputStream`.
+ *
+ * @param [in,out] streamPtr is a pointer to the `PARCFileOutputStream` reference.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcFileOutputStream_Release(PARCFileOutputStream **streamPtr);
+
+/**
+ * Write the contents of a {@link PARCBuffer} to the given `PARCFileOutputStream`.
+ *
+ * The contents of the `PARCBuffer` from the current position to the limit are written to the `PARCFileOutputStream`.
+ * When this function returns the position is set to the end of the last successfully written byte of data.
+ *
+ * @param [in,out] outputStream The `PARCOutputStream` to write to.
+ * @param [in] buffer The `PARCBuffer` to write, from the current position of the buffer to its limit.
+ *
+ * @return true The entire contents of the `PARCBuffer` were written.
+ * @return false The entire contents of the `PARCBuffer` were not written.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *stream =
+ * parcFileOutputStream_Create(open("/tmp/test_parc_FileOutputStream", O_CREAT|O_WRONLY|O_TRUNC, 0600));
+ *
+ * PARCBuffer *buffer = parcBuffer_Allocate(16 * 1024*1024);
+ *
+ * parcFileOutputStream_Write(stream, buffer);
+ *
+ * assertFalse(parcBuffer_HasRemaining(buffer), "Expected the buffer to be emtpy");
+ *
+ * parcBuffer_Release(&buffer);
+ *
+ * parcFileOutputStream_Release(&stream);
+ * }
+ * @endcode
+ */
+bool parcFileOutputStream_Write(PARCFileOutputStream *outputStream, PARCBuffer *buffer);
+#endif // libparc_parc_FileOutputStream_h
diff --git a/libparc/parc/algol/parc_Hash.c b/libparc/parc/algol/parc_Hash.c
new file mode 100755
index 00000000..1884c74c
--- /dev/null
+++ b/libparc/parc/algol/parc_Hash.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.
+ */
+
+/**
+ * This hash is based on FNV-1a, using different lengths. Please see the FNV-1a
+ * website for details on the algorithm: http://www.isthe.com/chongo/tech/comp/fnv
+ *
+ */
+#include <config.h>
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Object.h>
+
+struct parc_hash_32bits {
+ uint32_t accumulator;
+};
+
+parcObject_ExtendPARCObject(PARCHash32Bits, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCHash32Bits *
+parcHash32Bits_Create(void)
+{
+ PARCHash32Bits *result = parcObject_CreateInstance(PARCHash32Bits);
+ if (result != NULL) {
+ result->accumulator = 0;
+ }
+
+ return result;
+}
+
+PARCHash32Bits *
+parcHash32Bits_Update(PARCHash32Bits *hash, const void *data, size_t length)
+{
+ hash->accumulator = parcHash32_Data_Cumulative(data, length, hash->accumulator);
+ return hash;
+}
+
+PARCHash32Bits *
+parcHash32Bits_UpdateUint32(PARCHash32Bits *hash, uint32_t value)
+{
+ hash->accumulator = parcHash32_Data_Cumulative(&value, sizeof(value), hash->accumulator);
+ return hash;
+}
+
+uint32_t
+parcHash32Bits_Hash(PARCHash32Bits *hash)
+{
+ return hash->accumulator;
+}
+
+parcObject_ImplementAcquire(parcHash32Bits, PARCHash32Bits);
+
+parcObject_ImplementRelease(parcHash32Bits, PARCHash32Bits);
+
+/*
+ * Based on 64-bit FNV-1a
+ */
+uint64_t
+parcHash64_Data(const void *data, size_t len)
+{
+ // Standard FNV 64-bit offset: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
+ const uint64_t fnv1a_offset = 0xCBF29CE484222325ULL;
+ return parcHash64_Data_Cumulative(data, len, fnv1a_offset);
+}
+
+uint64_t
+parcHash64_Data_Cumulative(const void *data, size_t len, uint64_t lastValue)
+{
+ // Standard FNV 64-bit prime: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
+ const uint64_t fnv1a_prime = 0x00000100000001B3ULL;
+ uint64_t hash = lastValue;
+ const char *chardata = data;
+
+ for (size_t i = 0; i < len; i++) {
+ hash = hash ^ chardata[i];
+ hash = hash * fnv1a_prime;
+ }
+
+ return hash;
+}
+
+uint64_t
+parcHash64_Int64(uint64_t int64)
+{
+ return parcHash64_Data(&int64, sizeof(uint64_t));
+}
+
+uint64_t
+parcHash64_Int32(uint32_t int32)
+{
+ return parcHash64_Data(&int32, sizeof(uint32_t));
+}
+
+uint32_t
+parcHash32_Data(const void *data, size_t len)
+{
+ // Standard FNV 32-bit offset: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
+ const uint32_t fnv1a_offset = 0x811C9DC5;
+ return parcHash32_Data_Cumulative(data, len, fnv1a_offset);
+}
+
+uint32_t
+parcHash32_Data_Cumulative(const void *data, size_t len, uint32_t lastValue)
+{
+ // Standard FNV 32-bit prime: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
+ const uint32_t fnv1a_prime = 0x01000193;
+ uint32_t hash = lastValue;
+
+ const char *chardata = data;
+
+ for (size_t i = 0; i < len; i++) {
+ hash = hash ^ chardata[i];
+ hash = hash * fnv1a_prime;
+ }
+
+ return hash;
+}
+
+uint32_t
+parcHash32_Int64(uint64_t int64)
+{
+ return parcHash32_Data(&int64, sizeof(uint64_t));
+}
+
+uint32_t
+parcHash32_Int32(uint32_t int32)
+{
+ return parcHash32_Data(&int32, sizeof(uint32_t));
+}
diff --git a/libparc/parc/algol/parc_Hash.h b/libparc/parc/algol/parc_Hash.h
new file mode 100755
index 00000000..92227041
--- /dev/null
+++ b/libparc/parc/algol/parc_Hash.h
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Hash.h
+ * @ingroup datastructures
+ * @brief Implements the FNV-1a 64-bit and 32-bit hashes.
+ *
+ * These are some basic hashing functions for blocks of data and integers. They
+ * generate 64 and 32 bit hashes (They are currently using the FNV-1a algorithm.)
+ * There is also a cumulative version of the hashes that can be used if intermediary
+ * hashes are required/useful.
+ *
+ */
+#ifndef libparc_parc_Hash_h
+#define libparc_parc_Hash_h
+
+#include <stdint.h>
+#include <stdlib.h>
+
+
+struct parc_hash_32bits;
+/**
+ * @typedef PARCHash32Bits
+ * @brief An accumulator
+ */
+
+typedef struct parc_hash_32bits PARCHash32Bits;
+
+/**
+ * Create a 32 bit hash generator
+ *
+ * @return A pointer to a `PARCHash32Bits` instance
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCHash32Bits *parcHash32Bits_Create(void);
+
+/**
+ * Generate a 32 bit hash from a memory block starting with a previous hash
+ *
+ * This is a typed version of {@link parcHash32_Data_Cumulative}
+ *
+ * @param [in] hash the value of the last cumulative hash calculated
+ * @param [in] data pointer to a memory block.
+ * @param [in] length length of the memory pointed to by data
+ *
+ * @return pointer to a {@link PARCHash32Bits} with the cumulative hash
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCHash32Bits *parcHash32Bits_Update(PARCHash32Bits *hash, const void *data, size_t length);
+
+/**
+ * Generate a 32 bit hash from a uint32 starting with a previous hash
+ * Update the cumulative state of the given {@link PARCHash32Bits}
+ *
+ * @param [in] hash the value of the last cumulative hash calculated
+ * @param [in] value The `uint32` to be hashed
+ *
+ * @return pointer to a `PARCHash32Bits` with the cumulative hash
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCHash32Bits *parcHash32Bits_UpdateUint32(PARCHash32Bits *hash, uint32_t value);
+
+/**
+ * Get the current value of the cummulative state of the given {@link PARCHash32Bits}.
+ *
+ * @param [in] hash the value of the last cumulative hash calculated
+ *
+ * @return The hash value as an unsigned 32 bit integer
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+uint32_t parcHash32Bits_Hash(PARCHash32Bits *hash);
+
+/**
+ * Acquire a new reference to the given {@link PARCHash32Bits} instance.
+ *
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] hash The instance of `PARCHash32Bits` to which to refer.
+ *
+ * @return The same value as the input parameter @p hash
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCHash32Bits *parcHash32Bits_Acquire(const PARCHash32Bits *hash);
+
+/**
+ * Release a reference to the given {@link PARCHash32Bits} instance.
+ *
+ * Only the last invocation where the reference count is decremented to zero,
+ * will actually destroy the `PARCHash32Bits`.
+ *
+ * @param [in,out] hash is a pointer to the `PARCHash32Bits` reference.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcHash32Bits_Release(PARCHash32Bits **hash);
+
+/**
+ * Generate a 64 bit hash from a memory block
+ *
+ * This function will generate a 64bit hash from a block of memory. The memory block
+ * is not modified in any way.
+ *
+ * The output of this function can be used as input for the cumulative version of
+ * this function
+ *
+ * @param [in] data A pointer to a memory block.
+ * @param [in] len The length of the memory pointed to by data
+ *
+ * @return hash_64bit A 64 bit hash of the memory block.
+ *
+ * Example:
+ * @code
+ *
+ * char * data = "Hello world of hashing";
+ * uint64_t myhash = parcHash64_Data(data,strlen(data));
+ *
+ * @endcode
+ *
+ * @see {@link parcHash64_Data_Cumulative}
+ */
+uint64_t parcHash64_Data(const void *data, size_t len);
+
+/**
+ * Generate a 64 bit hash from a memory block starting with a previous hash
+ *
+ * This function will generate a 64 bit hash from a block of memory and an initial
+ * hash. This is used to cumulatively calculate a hash of larger block. So,
+ * one could generate the hash of the first part of the data (A), then calculate the
+ * hash including the next part of the data (AB) and then the hash of the next
+ * part (ABC). This is useful for not having to recalculate the hash of the parts
+ * you have already hashed.
+ *
+ * A cumulative hash should have the same value as a full hash of the complete data.
+ * So cumulative_hash(B,len(B),hash(A)) is equal to hash(AB,len(AB)).
+ *
+ * @param [in] data pointer to a memory block.
+ * @param [in] len length of the memory pointed to by data
+ * @param [in] lastValue the vale of the last cumulative hash calculated
+ *
+ * @return cumulative_hash64 A 64 bit hash of the data _and_ the data that was
+ * hashed before (represented by lastValue).
+ *
+ * Example:
+ * @code
+ *
+ * char * data1 = "1234567890";
+ * uint64_t myhash1 = parcHash64_Data(data1,10);
+ * char * data2 = "abcdefghij";
+ * uint64_t myhash2 = parcHash64_Data_Cumulative(data2,10,myhash1);
+ * char * data3 = "1234567890abcdefghij";
+ * uint64_t myhash3 = parcHash64_Data(data3,20);
+ * // myhash3 will be equal to myhash2
+ *
+ * @endcode
+ *
+ * @see {@link parcHash64_Data}
+ */
+uint64_t parcHash64_Data_Cumulative(const void *data, size_t len, uint64_t lastValue);
+
+/**
+ * Generate a 64 bit hash from a 64 bit Integer
+ *
+ * This function hashes a 64 bit integer into a 64 bit hash
+ *
+ * @param [in] int64 A 64 bit integer
+ *
+ * @return hash64 A 64 bit hash of the 64 bit integer
+ *
+ * Example:
+ * @code
+ * uint64_t id64 = 1234567890123456;
+ * uint64_t hash64 = parcHash64_Int64(id64);
+ * @endcode
+ *
+ */
+uint64_t parcHash64_Int64(uint64_t int64);
+
+/**
+ * Generate a 64 bit hash from a 32 bit Integer
+ *
+ * This function hashes a 32 bit integer into a 64 bit hash
+ *
+ * @param [in] int32 A 32 bit integer
+ *
+ * @return hash64 A 64 bit hash of the 32 bit integer
+ *
+ * Example:
+ * @code
+ * uint32_t id32 = 70;
+ * uint64_t hash64 = parcHash64_Int32(id32);
+ * @endcode
+ *
+ */
+uint64_t parcHash64_Int32(uint32_t int32);
+
+/**
+ * Generate a 32 bit hash from a memory block
+ *
+ * This function will generate a 32bit hash from a block of memory. The memory block
+ * is not modified in any way.
+ * The output of this function can be used as input for the cumulative version of
+ * this function.
+ *
+ * @param [in] data pointer to a memory block.
+ * @param [in] len length of the memory pointed to by data
+ *
+ * @return hash_32bit A 32 bit hash of the memory block.
+ *
+ * Example:
+ * @code
+ *
+ * char * data = "Hello world of hashing";
+ * uint32_t myhash = parcHash32_Data(data,strlen(data));
+ *
+ * @endcode
+ *
+ * @see {@link parcHash32_Data_Cumulative}
+ */
+uint32_t parcHash32_Data(const void *data, size_t len);
+
+/**
+ * Generate a 32 bit hash from a memory block starting with a previous hash
+ *
+ * This function will generate a 32 bit hash from a block of memory and an initial
+ * hash. This is used to cumulatively calculate a hash of larger block. So,
+ * one could generate the hash of the first part of the data (A), then calculate the
+ * hash including the next part of the data (AB) and then the hash of the next
+ * part (ABC). This is useful for not having to recalculate the hash of the parts
+ * you have already hashed.
+ *
+ * A cumulative hash should have the same value as a full hash of the complete data.
+ * So cumulative_hash(B,len(B),hash(A)) is equal to hash(AB,len(AB)).
+ *
+ * @param [in] data pointer to a memory block.
+ * @param [in] len length of the memory pointed to by data
+ * @param [in] lastValue the vale of the last cumulative hash calculated
+ *
+ * @return cumulative_hash32 A 32 bit hash of the data _and_ the data that was
+ * hashed before (represented by lastValue).
+ *
+ * Example:
+ * @code
+ *
+ * char * data1 = "1234567890";
+ * uint32_t myhash1 = parcHash32_Data(data1,10);
+ * char * data2 = "abcdefghij";
+ * uint32_t myhash2 = parcHash32_Data_Cumulative(data2,10,myhash1);
+ * char * data3 = "1234567890abcdefghij";
+ * uint32_t myhash3 = parcHash32_Data(data3,20);
+ * // myhash3 will be equal to myhash2
+ *
+ * @endcode
+ *
+ * @see {@link parcHash32_Data}
+ */
+uint32_t parcHash32_Data_Cumulative(const void *data, size_t len, uint32_t lastValue);
+
+/**
+ * Generate a 32 bit hash from a 64 bit Integer
+ *
+ * This function hashes a 64 bit integer into a 32 bit hash
+ *
+ * @param [in] int64 A 64 bit integer
+ *
+ * @return hash32 A 32 bit hash of the 64 bit integer
+ *
+ * Example:
+ * @code
+ * uint64_t id64 = 1234567890123456;
+ * uint32_t hash32 = parcHash32_Int64(id64);
+ * @endcode
+ *
+ */
+uint32_t parcHash32_Int64(uint64_t int64);
+
+/**
+ * Generate a 32 bit hash from a 32 bit Integer
+ *
+ * This function hashes a 32 bit integer into a 32 bit hash
+ *
+ * @param [in] int32 A 32 bit integer
+ *
+ * @return hash32 A 32 bit hash of the 32 bit integer
+ *
+ * Example:
+ * @code
+ * uint32_t id32 = 1234567890123456;
+ * uint32_t hash32 = parcHash32_Int32(id32);
+ * @endcode
+ *
+ */
+uint32_t parcHash32_Int32(uint32_t int32);
+#endif // libparc_parc_Hash_h
diff --git a/libparc/parc/algol/parc_HashCode.c b/libparc/parc/algol/parc_HashCode.c
new file mode 100755
index 00000000..8554429c
--- /dev/null
+++ b/libparc/parc/algol/parc_HashCode.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <parc/algol/parc_HashCode.h>
+
+#if PARCHashCodeSize == 64
+static const PARCHashCode _fnv1a_prime = 0x00000100000001B3ULL;
+const PARCHashCode parcHashCode_InitialValue = 0xCBF29CE484222325ULL;
+#else
+static const PARCHashCode _fnv1a_prime = 0x01000193;
+const PARCHashCode parcHashCode_InitialValue = 0x811C9DC5;
+#endif
+
+PARCHashCode
+parcHashCode_HashImpl(const uint8_t *memory, size_t length, PARCHashCode initialValue)
+{
+ // Standard FNV 64-bit prime: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
+
+ PARCHashCode hash = initialValue;
+
+ for (size_t i = 0; i < length; i++) {
+ hash = hash ^ memory[i];
+ hash = hash * _fnv1a_prime;
+ }
+
+ return hash;
+}
+
+PARCHashCode
+parcHashCode_HashHashCode(PARCHashCode initialValue, PARCHashCode update)
+{
+ return parcHashCode_HashImpl((uint8_t *) &update, sizeof(PARCHashCode), initialValue);
+}
diff --git a/libparc/parc/algol/parc_HashCode.h b/libparc/parc/algol/parc_HashCode.h
new file mode 100755
index 00000000..dd572bee
--- /dev/null
+++ b/libparc/parc/algol/parc_HashCode.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_HashCode.h
+ * @ingroup object
+ * @brief The type returned from implementations of the _HashCode() function.
+ *
+ * The size of a PARCHashCode value may be different depending on the compile-time compilation environment.
+ *
+ */
+#ifndef PARC_Library_parc_HashCode_h
+#define PARC_Library_parc_HashCode_h
+
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#define PARCHashCodeSize 64
+//#define PARCHashCodeSize 32
+
+/**
+ * @typedef PARCHashCode
+ * @brief The type returned from implementations of the _HashCode() function.
+ */
+#if PARCHashCodeSize == 64
+#define PRIPARCHashCode PRIu64
+#define PRIXPARCHashCode PRIX64
+#define PRIxPARCHashCode PRIx64
+typedef uint64_t PARCHashCode;
+
+#else
+#define PRIPARCHashCode PRIu32
+#define PRIXPARCHashCode PRIX32
+#define PRIxPARCHashCode PRIx32
+typedef uint32_t PARCHashCode;
+
+#endif
+
+extern const PARCHashCode parcHashCode_InitialValue;
+
+#define parcHashCode_Hash(_memory_, _length_) parcHashCode_HashImpl(_memory_, _length_, parcHashCode_InitialValue)
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] memory A pointer to bytes used to generate the `PARCHashCode`.
+ * @param [in] length The number of bytes in memory to use to generate the `PARCHashCode`
+ * @param [in] initialValue An inital value for the `PARCHashCode`.
+ *
+ * @return The resulting `PARCHashCode` value.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCHashCode parcHashCode_HashImpl(const uint8_t *memory, size_t length, PARCHashCode initialValue);
+
+/**
+ * Hash a PARcHashCode into an existing PARCHashCode.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] initialValue The PARCHashCode initial value
+ * @param [in] update The PARCHashCode value to update the initial value.
+ *
+ * @return The updated PARCHashCode value
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCHashCode parcHashCode_HashHashCode(PARCHashCode initialValue, PARCHashCode update);
+#endif
diff --git a/libparc/parc/algol/parc_HashCodeTable.c b/libparc/parc/algol/parc_HashCodeTable.c
new file mode 100755
index 00000000..ea1945b3
--- /dev/null
+++ b/libparc/parc/algol/parc_HashCodeTable.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 an open-addressing hash table. We use linear probing of +1 per step.
+ *
+ * Table is rehashed when we reach 75% utilization.
+ * The table is rehashed if we go more than 10 linear probes without being able to insert.
+ *
+ * HashCodeTable is a wrapper that holds the key/data management functions. It also
+ * has LinearAddressingHashTable that is the actual hash table.
+ *
+ * This open-addressing table is inefficient for GET or DEL if the element does not exist.
+ * The whole table needs to be
+ *
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/algol/parc_HashCodeTable.h>
+#include <parc/algol/parc_Memory.h>
+
+// minimum size if nothing specified
+#define MIN_SIZE 256
+
+// when we expand, use this factor
+#define EXPAND_FACTOR 2
+
+#define MAX_PROBE_LENGTH 20
+
+typedef enum {
+ ADD_OK, // we added the key
+ ADD_DUP, // the key is a duplicate
+ ADD_NOSPACE // ran out of space
+} PARCHashCodeTable_AddResult;
+
+typedef struct hashtable_entry {
+ // A hashtable entry is in use if the key is non-null
+ void *key;
+ void *data;
+ HashCodeType hashcode;
+} HashTableEntry;
+
+typedef struct linear_address_hash_table {
+ HashTableEntry *entries;
+
+ // Number of elements allocated
+ size_t tableLimit;
+
+ // Number of elements in use
+ size_t tableSize;
+
+ // When the tableSize equals or exceeds this
+ // threshold, we should expand and re-hash the table∫
+ size_t expandThreshold;
+} LinearAddressingHashTable;
+
+struct parc_hashcode_table {
+ LinearAddressingHashTable hashtable;
+
+ PARCHashCodeTable_KeyEqualsFunc keyEqualsFunc;
+ PARCHashCodeTable_HashCodeFunc keyHashCodeFunc;
+ PARCHashCodeTable_Destroyer keyDestroyer;
+ PARCHashCodeTable_Destroyer dataDestroyer;
+
+ unsigned expandCount;
+};
+
+static bool
+_findIndex(PARCHashCodeTable *table, const void *key, size_t *outputIndexPtr)
+{
+ size_t index, start;
+ HashCodeType hashcode;
+ LinearAddressingHashTable *innerTable;
+
+ innerTable = &table->hashtable;
+ hashcode = table->keyHashCodeFunc(key);
+ index = hashcode % innerTable->tableLimit;
+ start = index;
+
+
+ // check until we've gone MAX_PROBE_LENGTH
+ unsigned steps = 0;
+ do {
+ if (innerTable->entries[index].key != NULL) {
+ if ((innerTable->entries[index].hashcode == hashcode) && table->keyEqualsFunc(key, innerTable->entries[index].key)) {
+ // the key already exists in the table
+ *outputIndexPtr = index;
+ return true;
+ }
+ }
+ steps++;
+ index = index + 1;
+ if (index == innerTable->tableLimit) {
+ index = 0;
+ }
+ } while (index != start && steps < MAX_PROBE_LENGTH);
+
+ return false;
+}
+
+static PARCHashCodeTable_AddResult
+_innerTableAdd(LinearAddressingHashTable *innerTable, PARCHashCodeTable_KeyEqualsFunc keyEqualsFunc,
+ HashCodeType hashcode, void *key, void *data)
+{
+ size_t index = hashcode % innerTable->tableLimit;
+
+ unsigned steps = 0;
+
+ // we know the size < limit, so it will fit eventually
+ while (steps < MAX_PROBE_LENGTH) {
+ if (innerTable->entries[index].key == NULL) {
+ innerTable->entries[index].hashcode = hashcode;
+ innerTable->entries[index].key = key;
+ innerTable->entries[index].data = data;
+ innerTable->tableSize++;
+ return ADD_OK;
+ }
+
+ if ((innerTable->entries[index].hashcode == hashcode) && keyEqualsFunc(key, innerTable->entries[index].key)) {
+ // the key already exists in the table
+ return ADD_DUP;
+ }
+
+ steps++;
+ index = index + 1;
+ if (index == innerTable->tableLimit) {
+ index = 0;
+ }
+ }
+
+ return ADD_NOSPACE;
+}
+
+static PARCHashCodeTable_AddResult
+_rehash(LinearAddressingHashTable *old_table, LinearAddressingHashTable *new_table, PARCHashCodeTable_KeyEqualsFunc keyEqualsFunc)
+{
+ size_t i;
+ for (i = 0; i < old_table->tableLimit; i++) {
+ if (old_table->entries[i].key != NULL) {
+ PARCHashCodeTable_AddResult result = _innerTableAdd(new_table, keyEqualsFunc, old_table->entries[i].hashcode,
+ old_table->entries[i].key, old_table->entries[i].data);
+ if (result != ADD_OK) {
+ return result;
+ }
+ }
+ }
+ return ADD_OK;
+}
+
+static void
+_expand(PARCHashCodeTable *hashCodeTable)
+{
+ LinearAddressingHashTable temp_table;
+ LinearAddressingHashTable *old_table = &hashCodeTable->hashtable;
+
+ size_t expandby = EXPAND_FACTOR;
+
+ // start with a copy of the current table
+ PARCHashCodeTable_AddResult result = ADD_OK;
+ do {
+ hashCodeTable->expandCount++;
+
+ temp_table.tableSize = 0;
+ temp_table.tableLimit = old_table->tableLimit * expandby;
+ temp_table.expandThreshold = temp_table.tableLimit - temp_table.tableLimit / 4;
+ temp_table.entries = parcMemory_AllocateAndClear(temp_table.tableLimit * sizeof(HashTableEntry));
+ assertNotNull(temp_table.entries, "parcMemory_AllocateAndClear(%zu) returned NULL", temp_table.tableLimit * sizeof(HashTableEntry));
+
+ result = _rehash(old_table, &temp_table, hashCodeTable->keyEqualsFunc);
+ if (result == ADD_NOSPACE) {
+ // could not rehash, so expand by more and try again
+ parcMemory_Deallocate((void **) &(temp_table.entries));
+ expandby++;
+ }
+ } while (result == ADD_NOSPACE);
+
+ parcMemory_Deallocate((void **) &old_table->entries);
+ hashCodeTable->hashtable = temp_table;
+}
+
+PARCHashCodeTable *
+parcHashCodeTable_Create_Size(PARCHashCodeTable_KeyEqualsFunc keyEqualsFunc,
+ PARCHashCodeTable_HashCodeFunc keyHashCodeFunc,
+ PARCHashCodeTable_Destroyer keyDestroyer,
+ PARCHashCodeTable_Destroyer dataDestroyer,
+ size_t minimumSize)
+{
+ PARCHashCodeTable *table = parcMemory_AllocateAndClear(sizeof(PARCHashCodeTable));
+ assertNotNull(table, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCHashCodeTable));
+
+ assertNotNull(keyEqualsFunc, "keyEqualsFunc must be non-null");
+ assertNotNull(keyHashCodeFunc, "keyHashCodeFunc must be non-null");
+ assertTrue(minimumSize > 0, "minimumSize must be greater than zero");
+
+ table->keyEqualsFunc = keyEqualsFunc;
+ table->keyHashCodeFunc = keyHashCodeFunc;
+ table->keyDestroyer = keyDestroyer;
+ table->dataDestroyer = dataDestroyer;
+
+ table->hashtable.entries = parcMemory_AllocateAndClear(minimumSize * sizeof(HashTableEntry));
+ assertNotNull(table->hashtable.entries, "parcMemory_AllocateAndClear(%zu) returned NULL", minimumSize * sizeof(HashTableEntry));
+ table->hashtable.tableLimit = minimumSize;
+ table->hashtable.tableSize = 0;
+
+ memset(table->hashtable.entries, 0, minimumSize * sizeof(HashTableEntry));
+
+ // expand at 75% utilization
+ table->hashtable.expandThreshold = minimumSize - minimumSize / 4;
+
+ return table;
+}
+
+PARCHashCodeTable *
+parcHashCodeTable_Create(PARCHashCodeTable_KeyEqualsFunc keyEqualsFunc,
+ PARCHashCodeTable_HashCodeFunc keyHashCodeFunc,
+ PARCHashCodeTable_Destroyer keyDestroyer,
+ PARCHashCodeTable_Destroyer dataDestroyer)
+{
+ return parcHashCodeTable_Create_Size(keyEqualsFunc, keyHashCodeFunc, keyDestroyer, dataDestroyer, MIN_SIZE);
+}
+
+void
+parcHashCodeTable_Destroy(PARCHashCodeTable **tablePtr)
+{
+ assertNotNull(tablePtr, "Parameter must be non-null double pointer");
+ assertNotNull(*tablePtr, "Parameter must dereference to non-null pointer");
+ PARCHashCodeTable *table = *tablePtr;
+ size_t i;
+
+ for (i = 0; i < table->hashtable.tableLimit; i++) {
+ if (table->hashtable.entries[i].key != NULL) {
+ if (table->keyDestroyer) {
+ table->keyDestroyer(&table->hashtable.entries[i].key);
+ }
+
+ if (table->dataDestroyer) {
+ table->dataDestroyer(&table->hashtable.entries[i].data);
+ }
+ }
+ }
+
+ parcMemory_Deallocate((void **) &(table->hashtable.entries));
+ parcMemory_Deallocate((void **) &table);
+ *tablePtr = NULL;
+}
+
+bool
+parcHashCodeTable_Add(PARCHashCodeTable *table, void *key, void *data)
+{
+ assertNotNull(table, "Parameter table must be non-null");
+ assertNotNull(key, "Parameter key must be non-null");
+ assertNotNull(data, "Parameter data must be non-null");
+
+ if (table->hashtable.tableSize >= table->hashtable.expandThreshold) {
+ _expand(table);
+ }
+
+ HashCodeType hashcode = table->keyHashCodeFunc(key);
+
+ PARCHashCodeTable_AddResult result = ADD_OK;
+ do {
+ result = _innerTableAdd(&table->hashtable, table->keyEqualsFunc, hashcode, key, data);
+ if (result == ADD_NOSPACE) {
+ _expand(table);
+ }
+ } while (result == ADD_NOSPACE);
+
+ return (result == ADD_OK);
+}
+
+void
+parcHashCodeTable_Del(PARCHashCodeTable *table, const void *key)
+{
+ size_t index;
+ bool found;
+
+ assertNotNull(table, "Parameter table must be non-null");
+ assertNotNull(key, "parameter key must be non-null");
+
+ found = _findIndex(table, key, &index);
+
+ if (found) {
+ assertTrue(table->hashtable.tableSize > 0, "Illegal state: found entry in a hash table with 0 size");
+
+ if (table->keyDestroyer) {
+ table->keyDestroyer(&table->hashtable.entries[index].key);
+ }
+
+ if (table->dataDestroyer) {
+ table->dataDestroyer(&table->hashtable.entries[index].data);
+ }
+
+ memset(&table->hashtable.entries[index], 0, sizeof(HashTableEntry));
+
+ table->hashtable.tableSize--;
+ }
+}
+
+void *
+parcHashCodeTable_Get(PARCHashCodeTable *table, const void *key)
+{
+ size_t index;
+
+ assertNotNull(table, "Parameter table must be non-null");
+ assertNotNull(key, "parameter key must be non-null");
+
+ bool found = _findIndex(table, key, &index);
+
+ if (found) {
+ return table->hashtable.entries[index].data;
+ }
+
+ return NULL;
+}
+
+size_t
+parcHashCodeTable_Length(const PARCHashCodeTable *table)
+{
+ assertNotNull(table, "Parameter table must be non-null");
+ return table->hashtable.tableSize;
+}
diff --git a/libparc/parc/algol/parc_HashCodeTable.h b/libparc/parc/algol/parc_HashCodeTable.h
new file mode 100644
index 00000000..58b3d016
--- /dev/null
+++ b/libparc/parc/algol/parc_HashCodeTable.h
@@ -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.
+ */
+
+/**
+ * @file parc_HashCodeTable.h
+ * @ingroup datastructures
+ *
+ * A hashcode table requires the user to specify their own hash function
+ * to operate on the object type being inserted.
+ *
+ */
+#ifndef libparc_parc_HashCodeTable_h
+#define libparc_parc_HashCodeTable_h
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include <parc/algol/parc_HashCode.h>
+
+struct parc_hashcode_table;
+typedef struct parc_hashcode_table PARCHashCodeTable;
+
+typedef PARCHashCode HashCodeType;
+
+
+/**
+ * @typedef PARCHashCodeTable_KeyEqualsFunc
+ * @brief Are two keys equal?
+ *
+ */
+
+typedef bool (*PARCHashCodeTable_KeyEqualsFunc)(const void *keyA, const void *keyB);
+
+/**
+ * @typedef PARCHashCodeTable_HashCodeFunc
+ */
+
+typedef HashCodeType (*PARCHashCodeTable_HashCodeFunc)(const void *keyA);
+
+/**
+ * @typedef PARCHashCodeTable_Destroyer
+ */
+
+typedef void (*PARCHashCodeTable_Destroyer)(void **keyOrDataPtr);
+
+/**
+ * Create a Hash Table based on hash codes.
+ *
+ * @param [in] keyEqualsFunc Tests keys for equality.
+ * @param [in] keyHashCodeFunc Returns the hash code of a key
+ * @param [in] keyDestroyer Called on Remove or Destroy to free stored keys, may be NULL.
+ * @param [in] dataDestroyer Called on Remove or Destroy to free stored data, may be NULL.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCHashCodeTable *parcHashCodeTable_Create(PARCHashCodeTable_KeyEqualsFunc keyEqualsFunc,
+ PARCHashCodeTable_HashCodeFunc keyHashCodeFunc,
+ PARCHashCodeTable_Destroyer keyDestroyer,
+ PARCHashCodeTable_Destroyer dataDestroyer);
+
+
+/**
+ * Create a Hash Table based on hash codes.
+ *
+ * @param [in] keyEqualsFunc Tests keys for equality.
+ * @param [in] keyHashCodeFunc Returns the hash code of a key
+ * @param [in] keyDestroyer Called on Remove or Destroy to free stored keys, may be NULL.
+ * @param [in] dataDestroyer Called on Remove or Destroy to free stored data, may be NULL.
+ * @param [in] minimumSize The minimum size of the table
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCHashCodeTable *parcHashCodeTable_Create_Size(PARCHashCodeTable_KeyEqualsFunc keyEqualsFunc,
+ PARCHashCodeTable_HashCodeFunc keyHashCodeFunc,
+ PARCHashCodeTable_Destroyer keyDestroyer,
+ PARCHashCodeTable_Destroyer dataDestroyer,
+ size_t minimumSize);
+
+/**
+ * Destroy the table and free all saved objects
+ *
+ * @param [in,out] tablePtr is a pointer to the `PARCHashCodeTable` reference.
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcHashCodeTable_Destroy(PARCHashCodeTable **tablePtr);
+
+/**
+ * Add an element to the hash table.
+ * @param [in,out] table The key, must be usable with the {@link PARCHashCodeTable_KeyEqualsFunc} and {@link PARCHashCodeTable_HashCodeFunc}.
+ * @param [in] key The key, must be usable with the `keyEqualsFunc` and `keyHashCodeFunc`.
+ * @param [in] data The value, must not be NULL
+ *
+ * @return true if key did not exist and data was added. Returns false if key exists or error.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcHashCodeTable_Add(PARCHashCodeTable *table, void *key, void *data);
+
+/**
+ * Removes a key from an instance of `PARCHashCodeTable`, freeing key and data memory. Does nothing if key does not
+ * exist in the table.
+ *
+ * @param [in,out] table The instance of `PARCHashCodeTable` from which the key will be removed.
+ * @param [in] key The key, must be usable with the {@link PARCHashCodeTable_KeyEqualsFunc} and {@link PARCHashCodeTable_HashCodeFunc}.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcHashCodeTable_Del(PARCHashCodeTable *table, const void *key);
+
+/**
+ * Returns the key value, or NULL if the key does not exist
+ *
+ * @param [in] table The instance of `PARCHashCodeTable` from which the the value will be retrieved.
+ * @param [in] key The key to identify the desired value.
+ *
+ * @return A pointer to the value of the specified key.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcHashCodeTable_Get(PARCHashCodeTable *table, const void *key);
+
+/**
+ * Returns the number of entries in the table
+ *
+ *
+ * @param [in] table The specified `PARCHashCodeTable` instance.
+ * @return The number of entries in @p table.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcHashCodeTable_Length(const PARCHashCodeTable *table);
+#endif // libparc_parc_HashCodeTable_h
diff --git a/libparc/parc/algol/parc_HashMap.c b/libparc/parc/algol/parc_HashMap.c
new file mode 100644
index 00000000..35a4414f
--- /dev/null
+++ b/libparc/parc/algol/parc_HashMap.c
@@ -0,0 +1,666 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include "parc_HashMap.h"
+#include "parc_LinkedList.h"
+
+#include <math.h>
+
+static const uint32_t DEFAULT_CAPACITY = 43;
+
+typedef struct PARCHashMapEntry {
+ PARCObject *key;
+ PARCObject *value;
+} _PARCHashMapEntry;
+
+
+static bool
+_parcHashMapEntry_IsValid(_PARCHashMapEntry *hashEntry)
+{
+ bool result = false;
+
+ if (hashEntry) {
+ if (parcObject_IsValid(hashEntry->key)) {
+ if (parcObject_IsValid(hashEntry->value)) {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+static void
+_parcHashMapEntry_Finalize(_PARCHashMapEntry **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCHashMap pointer.");
+ _PARCHashMapEntry *hashMapEntry = *instancePtr;
+
+ _parcHashMapEntry_IsValid(hashMapEntry);
+
+ parcObject_Release(&hashMapEntry->key);
+ parcObject_Release(&hashMapEntry->value);
+}
+
+static bool
+_parcHashMapEntry_Equals(const _PARCHashMapEntry *a, const _PARCHashMapEntry *b)
+{
+ return (parcObject_Equals(a->key, b->key) && parcObject_Equals(a->value, b->value));
+}
+
+
+static PARCHashCode
+_parcHashMapEntry_HashCode(const _PARCHashMapEntry *entry)
+{
+ return parcObject_HashCode(entry->key);
+}
+
+
+struct PARCHashMap {
+ PARCLinkedList **buckets;
+ size_t minCapacity;
+ size_t capacity;
+ size_t size;
+ double maxLoadFactor;
+ double minLoadFactor;
+};
+
+static _PARCHashMapEntry *
+_parcHashMap_GetEntry(const PARCHashMap *hashMap, const PARCObject *key)
+{
+ PARCHashCode keyHash = parcObject_HashCode(key);
+
+ int bucket = keyHash % hashMap->capacity;
+
+ _PARCHashMapEntry *result = NULL;
+
+ if (hashMap->buckets[bucket] != NULL) {
+ PARCIterator *iterator = parcLinkedList_CreateIterator(hashMap->buckets[bucket]);
+
+ while (parcIterator_HasNext(iterator)) {
+ _PARCHashMapEntry *entry = parcIterator_Next(iterator);
+ if (parcObject_Equals(key, entry->key)) {
+ result = entry;
+ break;
+ }
+ }
+ parcIterator_Release(&iterator);
+ }
+
+ return result;
+}
+
+//static parcObject_ImplementAcquire(parcHashMapEntry, _PARCHashMapEntry);
+
+static parcObject_ImplementRelease(_parcHashMapEntry, _PARCHashMapEntry);
+
+parcObject_ExtendPARCObject(_PARCHashMapEntry, _parcHashMapEntry_Finalize, NULL, NULL, _parcHashMapEntry_Equals, NULL, _parcHashMapEntry_HashCode, NULL);
+
+static _PARCHashMapEntry *
+_parcHashMapEntry_Create(const PARCObject *key, const PARCObject *value)
+{
+ parcObject_OptionalAssertValid(key);
+ parcObject_OptionalAssertValid(value);
+
+ _PARCHashMapEntry *result = parcObject_CreateInstance(_PARCHashMapEntry);
+
+ result->key = parcObject_Copy(key);
+ result->value = parcObject_Acquire(value);
+
+ return result;
+}
+
+static void
+_parcHashMap_Finalize(PARCHashMap **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCHashMap pointer.");
+ PARCHashMap *hashMap = *instancePtr;
+
+ for (unsigned int i = 0; i < hashMap->capacity; i++) {
+ if (hashMap->buckets[i] != NULL) {
+ parcLinkedList_Release(&hashMap->buckets[i]);
+ }
+ }
+
+ parcMemory_Deallocate(&hashMap->buckets);
+
+ /* cleanup the instance fields here */
+}
+
+parcObject_ImplementAcquire(parcHashMap, PARCHashMap);
+
+parcObject_ImplementRelease(parcHashMap, PARCHashMap);
+
+parcObject_ExtendPARCObject(PARCHashMap, _parcHashMap_Finalize, parcHashMap_Copy, parcHashMap_ToString, parcHashMap_Equals, NULL, parcHashMap_HashCode, parcHashMap_ToJSON);
+
+void
+parcHashMap_AssertValid(const PARCHashMap *instance)
+{
+ assertTrue(parcHashMap_IsValid(instance),
+ "PARCHashMap is not valid.");
+}
+
+PARCHashMap *
+parcHashMap_CreateCapacity(unsigned int capacity)
+{
+ PARCHashMap *result = parcObject_CreateInstance(PARCHashMap);
+
+ if (result != NULL) {
+ if (capacity == 0) {
+ capacity = DEFAULT_CAPACITY;
+ }
+
+ result->minCapacity = capacity;
+ result->capacity = capacity;
+ result->size = 0;
+ result->maxLoadFactor = 0.75;
+ result->minLoadFactor = result->maxLoadFactor / 3.0;
+ result->buckets = parcMemory_AllocateAndClear(capacity * sizeof(PARCLinkedList*));
+ }
+
+ return result;
+}
+
+PARCHashMap *
+parcHashMap_Create(void)
+{
+ PARCHashMap *result = parcHashMap_CreateCapacity(DEFAULT_CAPACITY);
+
+ return result;
+}
+
+PARCHashMap *
+parcHashMap_Copy(const PARCHashMap *original)
+{
+ parcHashMap_OptionalAssertValid(original);
+
+ PARCHashMap *result = parcObject_CreateInstance(PARCHashMap);
+
+ result->capacity = original->capacity;
+ result->minCapacity = original->minCapacity;
+ result->maxLoadFactor = original->maxLoadFactor;
+ result->minLoadFactor = original->minLoadFactor;
+ result->size = original->size;
+ result->buckets = parcMemory_Allocate(result->capacity * sizeof(PARCLinkedList*));
+
+ for (unsigned int i = 0; i < result->capacity; i++) {
+ result->buckets[i] = NULL;
+ if (original->buckets[i] != NULL) {
+ result->buckets[i] = parcLinkedList_Copy(original->buckets[i]);
+ }
+ }
+
+ return result;
+}
+
+void
+parcHashMap_Display(const PARCHashMap *hashMap, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCHashMap@%p {", hashMap);
+
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator((PARCHashMap *) hashMap);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCObject *keyObject = parcIterator_Next(iterator);
+ const PARCObject *valueObject = parcHashMap_Get(hashMap, keyObject);
+ char *key = parcObject_ToString(keyObject);
+ char *value = parcObject_ToString(valueObject);
+ parcDisplayIndented_PrintLine(indentation + 1, "%s -> %s", key, value);
+ parcMemory_Deallocate(&key);
+ parcMemory_Deallocate(&value);
+ }
+ parcIterator_Release(&iterator);
+
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcHashMap_Equals(const PARCHashMap *x, const PARCHashMap *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ parcHashMap_OptionalAssertValid(x);
+ parcHashMap_OptionalAssertValid(y);
+
+ if (x->capacity == y->capacity) {
+ if (x->size == y->size) {
+ result = true;
+ for (unsigned int i = 0; (i < x->capacity) && result; i++) {
+ if ((x->buckets[i] == NULL) || (y->buckets[i] == NULL)) {
+ result = (x->buckets[i] == y->buckets[i]);
+ } else {
+ // For each item in an X bucket, it must be in the Y bucket.
+ result = parcLinkedList_SetEquals(x->buckets[i], y->buckets[i]);
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcHashMap_HashCode(const PARCHashMap *hashMap)
+{
+ parcHashMap_OptionalAssertValid(hashMap);
+
+ PARCHashCode result = 0;
+
+ for (unsigned int i = 0; i < hashMap->capacity; i++) {
+ if (hashMap->buckets[i] != NULL) {
+ result += parcLinkedList_HashCode(hashMap->buckets[i]);
+ }
+ }
+
+ return result;
+}
+
+bool
+parcHashMap_IsValid(const PARCHashMap *map)
+{
+ bool result = false;
+
+ if (map != NULL) {
+ if (parcObject_IsValid(map)) {
+ result = true;
+
+ for (unsigned int i = 0; i < map->capacity; i++) {
+ if (map->buckets[i] != NULL) {
+ if (parcLinkedList_IsValid(map->buckets[i]) == false) {
+ result = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcHashMap_ToJSON(const PARCHashMap *hashMap)
+{
+ parcHashMap_OptionalAssertValid(hashMap);
+
+ PARCJSON *result = parcJSON_Create();
+
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator((PARCHashMap *) hashMap);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCObject *keyObject = parcIterator_Next(iterator);
+ const PARCObject *valueObject = parcHashMap_Get(hashMap, keyObject);
+ char *key = parcObject_ToString(keyObject);
+ PARCJSON *value = parcObject_ToJSON(valueObject);
+
+ parcJSON_AddObject(result, key, value);
+
+ parcMemory_Deallocate(&key);
+ parcJSON_Release(&value);
+ }
+
+ parcIterator_Release(&iterator);
+
+
+ return result;
+}
+
+PARCBufferComposer *
+parcHashMap_BuildString(const PARCHashMap *hashMap, PARCBufferComposer *composer)
+{
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator((PARCHashMap *) hashMap);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCObject *keyObject = parcIterator_Next(iterator);
+ const PARCObject *valueObject = parcHashMap_Get(hashMap, keyObject);
+ char *key = parcObject_ToString(keyObject);
+ char *value = parcObject_ToString(valueObject);
+ parcBufferComposer_Format(composer, "%s -> %s\n", key, value);
+ parcMemory_Deallocate(&key);
+ parcMemory_Deallocate(&value);
+ }
+
+ parcIterator_Release(&iterator);
+
+ return composer;
+}
+
+char *
+parcHashMap_ToString(const PARCHashMap *hashMap)
+{
+ parcHashMap_OptionalAssertValid(hashMap);
+ char *result = NULL;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ if (composer != NULL) {
+ parcHashMap_BuildString(hashMap, composer);
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+ }
+
+ return result;
+}
+
+bool
+parcHashMap_Contains(PARCHashMap *hashMap, const PARCObject *key)
+{
+ PARCObject *result = NULL;
+
+ _PARCHashMapEntry *entry = _parcHashMap_GetEntry(hashMap, key);
+ if (entry != NULL) {
+ result = entry->value;
+ }
+
+ return result;
+}
+
+static void
+_parcHashMap_Resize(PARCHashMap *hashMap, size_t newCapacity)
+{
+ if (newCapacity < hashMap->minCapacity) {
+ return;
+ }
+
+ PARCLinkedList **newBuckets = parcMemory_AllocateAndClear(newCapacity * sizeof(PARCLinkedList*));
+
+ for (unsigned int i = 0; i < hashMap->capacity; i++) {
+ if (hashMap->buckets[i] != NULL) {
+ if (!parcLinkedList_IsEmpty(hashMap->buckets[i])) {
+ PARCIterator *elementIt = parcLinkedList_CreateIterator(hashMap->buckets[i]);
+ while (parcIterator_HasNext(elementIt)) {
+ _PARCHashMapEntry *entry = parcIterator_Next(elementIt);
+ PARCHashCode keyHash = parcObject_HashCode(entry->key);
+ int newBucket = keyHash % newCapacity;
+ if (newBuckets[newBucket] == NULL) {
+ newBuckets[newBucket] = parcLinkedList_Create();
+ }
+ parcLinkedList_Append(newBuckets[newBucket], entry);
+ }
+ parcIterator_Release(&elementIt);
+ }
+ parcLinkedList_Release(&hashMap->buckets[i]);
+ }
+ }
+ PARCLinkedList **cleanupBuckets = hashMap->buckets;
+ hashMap->buckets = newBuckets;
+ hashMap->capacity = newCapacity;
+
+ parcMemory_Deallocate(&cleanupBuckets);
+}
+
+bool
+parcHashMap_Remove(PARCHashMap *hashMap, const PARCObject *key)
+{
+ PARCHashCode keyHash = parcObject_HashCode(key);
+
+ int bucket = keyHash % hashMap->capacity;
+
+ bool result = false;
+
+ if (hashMap->buckets[bucket] != NULL) {
+ PARCIterator *iterator = parcLinkedList_CreateIterator(hashMap->buckets[bucket]);
+
+ while (parcIterator_HasNext(iterator)) {
+ _PARCHashMapEntry *entry = parcIterator_Next(iterator);
+ if (parcObject_Equals(key, entry->key)) {
+ parcIterator_Remove(iterator);
+ hashMap->size--;
+ result = true;
+ break;
+ }
+ }
+ parcIterator_Release(&iterator);
+ }
+
+ // When expanded by 2 the load factor goes from .75 (3/4) to .375 (3/8), if
+ // we compress by 2 when the load factor is .25 (1/4) the load
+ // factor becomes .5 (1/2).
+ double loadFactor = (double) hashMap->size / (double) hashMap->capacity;
+ if (loadFactor <= (hashMap->minLoadFactor)) {
+ _parcHashMap_Resize(hashMap, hashMap->capacity / 2);
+ }
+
+ return result;
+}
+
+#include <stdio.h>
+
+PARCHashMap *
+parcHashMap_Put(PARCHashMap *hashMap, const PARCObject *key, const PARCObject *value)
+{
+ // When expanded by 2 the load factor goes from .75 (3/4) to .375 (3/8), if
+ // we compress by 2 when the load factor is .25 (1/4) the load
+ // factor becomes .5 (1/2).
+ double loadFactor = (double) hashMap->size / (double) hashMap->capacity;
+ if (loadFactor >= hashMap->maxLoadFactor) {
+ _parcHashMap_Resize(hashMap, hashMap->capacity * 2);
+ }
+
+ _PARCHashMapEntry *entry = _parcHashMap_GetEntry(hashMap, key);
+
+ if (entry != NULL) {
+ if (entry->value != value) {
+ parcObject_Release(&entry->value);
+ entry->value = parcObject_Acquire(value);
+ }
+ } else {
+ entry = _parcHashMapEntry_Create(key, value);
+
+ PARCHashCode keyHash = parcObject_HashCode(key);
+ int bucket = keyHash % hashMap->capacity;
+
+ if (hashMap->buckets[bucket] == NULL) {
+ hashMap->buckets[bucket] = parcLinkedList_Create();
+ }
+ parcLinkedList_Append(hashMap->buckets[bucket], entry);
+ hashMap->size++;
+ _parcHashMapEntry_Release(&entry);
+ }
+
+ return hashMap;
+}
+
+const PARCObject *
+parcHashMap_Get(const PARCHashMap *hashMap, const PARCObject *key)
+{
+ PARCObject *result = NULL;
+
+ _PARCHashMapEntry *entry = _parcHashMap_GetEntry(hashMap, key);
+ if (entry != NULL) {
+ result = entry->value;
+ }
+
+ return result;
+}
+
+size_t
+parcHashMap_Size(const PARCHashMap *hashMap)
+{
+ parcHashMap_OptionalAssertValid(hashMap);
+ return hashMap->size;
+}
+
+double
+parcHashMap_GetClusteringNumber(const PARCHashMap *hashMap)
+{
+ // This function compute the standard deviation of the chain-lengths
+ // from a value of 1.0 (as opposed to the mean) and weights the
+ // result by in inverse of the current load factor. The deviation
+ // from 1.0 is used because the hashmap's max load factor is < 1.0 and
+ // thus the ideal average chain-length is 1.0
+ //
+ // A result of 0.0 equates to an ideal distribution, a result of ~1.0 should
+ // represent a fairly normal or random distribution, and a result > 1.5 or so
+ // implies some amount of undesirable clumping may be happening.
+
+ size_t totalLength = 0;
+ double variance = 0;
+
+ // Compute the variance vs 1.0
+ for (size_t i = 0; i < hashMap->capacity; ++i) {
+ if (hashMap->buckets[i] != NULL) {
+ size_t bucketSize = parcLinkedList_Size(hashMap->buckets[i]);
+ totalLength += bucketSize;
+ variance += (bucketSize - 1) * (bucketSize - 1); //Variance relative to 1
+ }
+ }
+ variance /= ((double) totalLength);
+
+ // Compute the standard deviation
+ double standardDeviation = sqrt(variance);
+
+ // Weight the standard deviation by the inverse of the current load factor
+ return standardDeviation * ((double) hashMap->capacity / (double) totalLength);
+}
+
+typedef struct {
+ PARCHashMap *map;
+ int bucket;
+ PARCIterator *listIterator;
+ _PARCHashMapEntry *current;
+} _PARCHashMapIterator;
+
+static _PARCHashMapIterator *
+_parcHashMap_Init(PARCHashMap *map __attribute__((unused)))
+{
+ _PARCHashMapIterator *state = parcMemory_AllocateAndClear(sizeof(_PARCHashMapIterator));
+
+ if (state != NULL) {
+ state->map = map;
+ state->bucket = 0;
+ state->listIterator = NULL;
+ for (size_t i = 0; i < map->capacity; ++i) {
+ if (map->buckets[i] != NULL) {
+ state->bucket = i;
+ state->listIterator = parcLinkedList_CreateIterator(map->buckets[i]);
+ break;
+ }
+ }
+
+ trapOutOfMemoryIf(state->listIterator == NULL, "Cannot create parcLinkedList_CreateIterator");
+ }
+
+ return state;
+}
+
+static bool
+_parcHashMap_Fini(PARCHashMap *map __attribute__((unused)), _PARCHashMapIterator *state __attribute__((unused)))
+{
+ if (state->listIterator != NULL) {
+ parcIterator_Release(&state->listIterator);
+ }
+ parcMemory_Deallocate(&state);
+ return true;
+}
+
+static _PARCHashMapIterator *
+_parcHashMap_Next(PARCHashMap *map __attribute__((unused)), _PARCHashMapIterator *state)
+{
+ _PARCHashMapEntry *result = parcIterator_Next(state->listIterator);
+ state->current = result;
+ return state;
+}
+
+static void
+_parcHashMap_Remove(PARCHashMap *map, _PARCHashMapIterator **statePtr __attribute__((unused)))
+{
+ _PARCHashMapIterator *state = *statePtr;
+
+ if (state->listIterator != NULL) {
+ parcIterator_Remove(state->listIterator);
+ map->size--;
+ }
+}
+
+static bool
+_parcHashMap_HasNext(PARCHashMap *map __attribute__((unused)), _PARCHashMapIterator *state)
+{
+ bool result = false;
+ if (state->listIterator != NULL) {
+ if (parcIterator_HasNext(state->listIterator)) {
+ result = true;
+ } else {
+ while ((result == false) && (++state->bucket < map->capacity)) {
+ if (map->buckets[state->bucket] != NULL) {
+ parcIterator_Release(&state->listIterator);
+ state->listIterator = parcLinkedList_CreateIterator(map->buckets[state->bucket]);
+ trapOutOfMemoryIf(state->listIterator == NULL, "Cannot create parcLinkedList_CreateIterator");
+ result = parcIterator_HasNext(state->listIterator);
+ }
+ }
+ }
+ }
+ return result;
+}
+
+static PARCObject *
+_parcHashMapValue_Element(PARCHashMap *map __attribute__((unused)), const _PARCHashMapIterator *state)
+{
+ return state->current->value;
+}
+
+static PARCObject *
+_parcHashMapKey_Element(PARCHashMap *map __attribute__((unused)), const _PARCHashMapIterator *state)
+{
+ return state->current->key;
+}
+
+PARCIterator *
+parcHashMap_CreateValueIterator(PARCHashMap *hashMap)
+{
+ PARCIterator *iterator = parcIterator_Create(hashMap,
+ (void *(*)(PARCObject *))_parcHashMap_Init,
+ (bool (*)(PARCObject *, void *))_parcHashMap_HasNext,
+ (void *(*)(PARCObject *, void *))_parcHashMap_Next,
+ (void (*)(PARCObject *, void **))_parcHashMap_Remove,
+ (void *(*)(PARCObject *, void *))_parcHashMapValue_Element,
+ (void (*)(PARCObject *, void *))_parcHashMap_Fini,
+ NULL);
+
+ return iterator;
+}
+
+
+PARCIterator *
+parcHashMap_CreateKeyIterator(PARCHashMap *hashMap)
+{
+ PARCIterator *iterator = parcIterator_Create(hashMap,
+ (void *(*)(PARCObject *))_parcHashMap_Init,
+ (bool (*)(PARCObject *, void *))_parcHashMap_HasNext,
+ (void *(*)(PARCObject *, void *))_parcHashMap_Next,
+ (void (*)(PARCObject *, void **))_parcHashMap_Remove,
+ (void *(*)(PARCObject *, void *))_parcHashMapKey_Element,
+ (void (*)(PARCObject *, void *))_parcHashMap_Fini,
+ NULL);
+
+ return iterator;
+}
diff --git a/libparc/parc/algol/parc_HashMap.h b/libparc/parc/algol/parc_HashMap.h
new file mode 100755
index 00000000..3ab26cd9
--- /dev/null
+++ b/libparc/parc/algol/parc_HashMap.h
@@ -0,0 +1,622 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_HashMap.h
+ * @ingroup datastructures
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_HashMap
+#define PARCLibrary_parc_HashMap
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_Iterator.h>
+
+struct PARCHashMap;
+typedef struct PARCHashMap PARCHashMap;
+
+/**
+ * Increase the number of references to a `PARCHashMap` instance.
+ *
+ * Note that new `PARCHashMap` is not created,
+ * only that the given `PARCHashMap` reference count is incremented.
+ * Discard the reference by invoking `parcHashMap_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCHashMap instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * PARCHashMap *b = parcHashMap_Acquire();
+ *
+ * parcHashMap_Release(&a);
+ * parcHashMap_Release(&b);
+ * }
+ * @endcode
+ */
+PARCHashMap *parcHashMap_Acquire(const PARCHashMap *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcHashMap_OptionalAssertValid(_instance_)
+#else
+# define parcHashMap_OptionalAssertValid(_instance_) parcHashMap_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCHashMap` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCHashMap instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * parcHashMap_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcHashMap_Release(&b);
+ * }
+ * @endcode
+ */
+void parcHashMap_AssertValid(const PARCHashMap *instance);
+
+/**
+ * Constructs an empty `PARCHashMap` with a default minimum number of 'buckets'.
+ *
+ * The capacity will expand and contract as needed to keep load factor table
+ * below the max load factor of 0.75 and above the minimum load factor or 0.25.
+ * The default minimum number of buckets is 42.
+ *
+ * @return non-NULL A pointer to a valid PARCHashMap instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * parcHashMap_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashMap *parcHashMap_Create(void);
+
+/**
+ * Constructs an empty `PARCHashMap` with the specified minimum number of 'buckets'.
+ *
+ * The capacity will expand and contract as needed to keep load factor table
+ * below the max load factor of 0.75 and above the minimum load factor or 0.25.
+ *
+ * @param [in] capacity The minimum number of buckets. Must be greater than 0.
+ *
+ * @return non-NULL A pointer to a valid PARCHashMap instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_CreateCapacity(43);
+ *
+ * parcHashMap_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashMap *parcHashMap_CreateCapacity(unsigned int capacity);
+
+/**
+ * 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 PARCHashMap instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCHashMap` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * PARCHashMap *copy = parcHashMap_Copy(&b);
+ *
+ * parcHashMap_Release(&b);
+ * parcHashMap_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCHashMap *parcHashMap_Copy(const PARCHashMap *original);
+
+/**
+ * Print a human readable representation of the given `PARCHashMap`.
+ *
+ * @param [in] instance A pointer to a valid PARCHashMap instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * parcHashMap_Display(a, 0);
+ *
+ * parcHashMap_Release(&a);
+ * }
+ * @endcode
+ */
+void parcHashMap_Display(const PARCHashMap *instance, int indentation);
+
+/**
+ * Determine if two `PARCHashMap` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCHashMap` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcHashMap_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcHashMap_Equals(x, y)` must return true if and only if
+ * `parcHashMap_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcHashMap_Equals(x, y)` returns true and
+ * `parcHashMap_Equals(y, z)` returns true,
+ * then `parcHashMap_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcHashMap_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcHashMap_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCHashMap instance.
+ * @param [in] y A pointer to a valid PARCHashMap instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ * PARCHashMap *b = parcHashMap_Create();
+ *
+ * if (parcHashMap_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcHashMap_Release(&a);
+ * parcHashMap_Release(&b);
+ * }
+ * @endcode
+ * @see parcHashMap_HashCode
+ */
+bool parcHashMap_Equals(const PARCHashMap *x, const PARCHashMap *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 parcHashMap_Equals} method,
+ * then calling the {@link parcHashMap_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 parcHashMap_Equals} function,
+ * then calling the `parcHashMap_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCHashMap instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * uint32_t hashValue = parcHashMap_HashCode(buffer);
+ * parcHashMap_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcHashMap_HashCode(const PARCHashMap *instance);
+
+/**
+ * Determine if an instance of `PARCHashMap` 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 PARCHashMap instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * if (parcHashMap_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcHashMap_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcHashMap_IsValid(const PARCHashMap *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCHashMap` 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
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * parcHashMap_Release(&a);
+ * }
+ * @endcode
+ */
+void parcHashMap_Release(PARCHashMap **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCHashMap 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
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * PARCJSON *json = parcHashMap_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcHashMap_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcHashMap_ToJSON(const PARCHashMap *instance);
+
+
+PARCBufferComposer *parcHashMap_BuildString(const PARCHashMap *hashMap, PARCBufferComposer *composer);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCHashMap`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCHashMap 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
+ * {
+ * PARCHashMap *a = parcHashMap_Create();
+ *
+ * char *string = parcHashMap_ToString(a);
+ *
+ * parcHashMap_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcHashMap_Display
+ */
+char *parcHashMap_ToString(const PARCHashMap *instance);
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcLinkedList_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] object A pointer to a valid PARCLinkedList instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcLinkedList_Notify(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotify(parcHashMap, PARCHashMap);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the parcHashMap_Notify() function on the same object.
+ * *
+ * @param [in] object A pointer to a valid `PARCHashMap` instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcHashMap_Wait(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementWait(parcHashMap, PARCHashMap);
+
+/**
+ * Obtain the lock on the given `PARCHashMap` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] object A pointer to a valid `PARCHashMap` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, or the `PARCHashMap` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcHashMap_Lock(object)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementLock(parcHashMap, PARCHashMap);
+
+/**
+ * Try to obtain the advisory lock on the given PARCHashMap instance.
+ *
+ * Once the lock is obtained, the caller must release the lock as soon as possible.
+ *
+ * @param [in] object A pointer to a valid PARCHashMap instance.
+ *
+ * @return true The PARCHashMap is locked.
+ * @return false The PARCHashMap is unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcHashMap_TryLock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementTryLock(parcHashMap, PARCHashMap);
+
+/**
+ * Try to unlock the advisory lock on the given `PARCHashMap` instance.
+ *
+ * @param [in] object A pointer to a valid `PARCHashMap` instance.
+ *
+ * @return true The `PARCHashMap` was locked and now is unlocked.
+ * @return false The `PARCHashMap` was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcHashMap_Unlock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementUnlock(parcHashMap, PARCHashMap);
+
+/**
+ * Determine if the advisory lock on the given `PARCHashMap` instance is locked.
+ *
+ * @param [in] object A pointer to a valid `PARCHashMap` instance.
+ *
+ * @return true The `PARCHashMap` is locked.
+ * @return false The `PARCHashMap` is unlocked.
+ * Example:
+ * @code
+ * {
+ * if (parcHashMap_IsLocked(object)) {
+ * ...
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementIsLocked(parcHashMap, PARCHashMap);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] hashMap A pointer to a valid PARCHashMap instance.
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCHashMap *parcHashMap_Put(PARCHashMap *hashMap, const PARCObject *key, const PARCObject *value);
+
+/**
+ * Returns the value to which the specified key is mapped,
+ * or null if this map contains no mapping for the key.
+ * If this map contains a mapping from a key _k_ to a value _v_ such that `(key==null ? k==null : key.equals(k))`,
+ * then this method returns _v_; otherwise it returns null. (There can be at most one such mapping.)
+ *
+ * A return value of `NULL` does not necessarily indicate that the map contains no mapping for the key.
+ * It is possible that the map explicitly maps the key to `NULL`.
+ * Use the `parcHashMap_ContainsKey` function to distinguish these cases.
+ *
+ * @param [in] hashMap A pointer to a valid PARCHashMap instance.
+ *
+ * @return The value to which the specified key is mapped, or `NULL` if this map contains no mapping for the key
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+const PARCObject *parcHashMap_Get(const PARCHashMap *hashMap, const PARCObject *key);
+
+/**
+ * Removes the mapping for the specified key from this `PARCHashMap`, if present.
+ *
+ * @param [in] hashMap A pointer to a valid PARCHashMap instance.
+ *
+ * @return true The key existed and was removed.
+ * @return true The key did not exist.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcHashMap_Remove(PARCHashMap *hashMap, const PARCObject *key);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] hashMap A pointer to a valid PARCHashMap instance.
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+size_t parcHashMap_Size(const PARCHashMap *hashMap);
+
+
+/**
+ * Computes the standard deviation of the PARCHashMap's bucket sizes from a value of 1.0
+ * (as opposed to the mean) and weighs the result by in inverse of the current load
+ * factor. The deviation from 1.0 is used because the hash-map's max load factor is < 1.0
+ * and thus the ideal average chain-length is 1.0.
+ *
+ * A result of 0.0 equates to an ideal distribution, a result of ~1.0 should represent
+ * a fairly normal or random distribution, and a result > 1.5 or so implies some amount
+ * of undesirable clumping may be happening.
+ *
+ * @param [in] hashMap A pointer to a valid PARCHashMap instance.
+ *
+ * @return The clustering number
+ */
+double parcHashMap_GetClusteringNumber(const PARCHashMap *hashMap);
+
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] hashMap A pointer to a valid PARCHashMap instance.
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcHashMap_Contains(PARCHashMap *hashMap, const PARCObject *key);
+
+/**
+ * Create a new instance of PARCIterator that iterates through the values of the specified `PARCHashMap`.
+ * The returned value must be released via {@link parcIterator_Release}.
+ *
+ * @param [in] hashMap A pointer to a valid `PARCHashMap`.
+ *
+ * @see parcIterator_Release
+ * Example:
+ * @code
+ * {
+ * PARCIterator *iterator = parcHashMap_CreateValueIterator(list);
+ *
+ * while (parcIterator_HasNext(iterator)) {
+ * PARCObject *object = parcIterator_Next(iterator);
+ * }
+ *
+ * parcIterator_Release(&iterator);
+ * }
+ * @endcode
+ */
+PARCIterator *parcHashMap_CreateValueIterator(PARCHashMap *hashMap);
+
+/**
+ * Create a new instance of PARCIterator that iterates through the keys of the specified `PARCHashMap`.
+ * The returned value must be released via {@link parcIterator_Release}.
+ *
+ * @param [in] hashMap A pointer to a valid `PARCHashMap`.
+ *
+ * @see parcIterator_Release
+ * Example:
+ * @code
+ * {
+ * PARCIterator *iterator = parcHashMap_CreateKeyIterator(list);
+ *
+ * while (parcIterator_HasNext(iterator)) {
+ * PARCObject *object = parcIterator_Next(iterator);
+ * }
+ *
+ * parcIterator_Release(&iterator);
+ * }
+ * @endcode
+ */
+PARCIterator *parcHashMap_CreateKeyIterator(PARCHashMap *hashMap);
+#endif
diff --git a/libparc/parc/algol/parc_InputStream.c b/libparc/parc/algol/parc_InputStream.c
new file mode 100755
index 00000000..ade5a46a
--- /dev/null
+++ b/libparc/parc/algol/parc_InputStream.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_InputStream.h>
+
+struct parc_input_stream {
+ void *instance;
+ const PARCInputStreamInterface *interface;
+};
+
+static void
+_destroy(PARCInputStream **inputStreamPtr)
+{
+ PARCInputStream *inputStream = *inputStreamPtr;
+ parcObject_Release(&inputStream->instance);
+}
+
+parcObject_ExtendPARCObject(PARCInputStream, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+
+PARCInputStream *
+parcInputStream(void *instance, const PARCInputStreamInterface *interface)
+{
+ PARCInputStream *result = parcObject_CreateInstance(PARCInputStream);
+ result->instance = instance;
+ result->interface = interface;
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcInputStream, PARCInputStream);
+
+parcObject_ImplementRelease(parcInputStream, PARCInputStream);
+
+size_t
+parcInputStream_Read(PARCInputStream *inputStream, PARCBuffer *buffer)
+{
+ return (inputStream->interface->Read)(inputStream->instance, buffer);
+}
diff --git a/libparc/parc/algol/parc_InputStream.h b/libparc/parc/algol/parc_InputStream.h
new file mode 100755
index 00000000..3ab6849a
--- /dev/null
+++ b/libparc/parc/algol/parc_InputStream.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_InputStream.h
+ * @ingroup inputoutput
+ * @brief Generalized Input Stream
+ *
+ * a `PARCFileInputStream` is a kind of `PARCInputStream`
+ *
+ */
+#ifndef libparc_parc_InputStream_h
+#define libparc_parc_InputStream_h
+
+#include <parc/algol/parc_Buffer.h>
+
+
+/**
+ * @typedef `PARCInputStream`
+ */
+struct parc_input_stream;
+typedef struct parc_input_stream PARCInputStream;
+
+/**
+ * @typedef PARCInputStreamInterface
+ */
+
+typedef struct parc_input_stream_interface {
+ size_t (*Read)(PARCInputStream *inputStream, PARCBuffer *buffer);
+
+ PARCInputStream *(*Acquire)(const PARCInputStream * instance);
+
+ void (*Release)(PARCInputStream **instancePtr);
+} PARCInputStreamInterface;
+
+/**
+ * Create an instance of a `PARCInputStream` given a pointer to an instance and interface.
+ *
+ *
+ * @param [in] instance A pointer to a structure suitable for the given `PARCInputStreamInterface`.
+ * @param [in] interface A pointer to a `PARCInputStreamInterface`
+ *
+ * @return non-NULL A pointer to a valid PARCInputStream
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+PARCInputStream *parcInputStream(void *instance, const PARCInputStreamInterface *interface);
+
+/**
+ * Read a `PARCInputStream` into a {@link PARCBuffer}.
+ *
+ * The contents of the `PARCBuffer` are filled from the current position to the limit.
+ * When this function returns the position is set to the end of the last successfully read byte of data.
+ *
+ * @param [in] inputStream The `PARCInputStream` to read.
+ * @param [in] buffer The `PARCBuffer` to fill, from the current position of the buffer to its limit.
+ *
+ * @return number of bytes read / filled.
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcInputStream_Read(PARCInputStream *inputStream, PARCBuffer *buffer);
+
+/**
+ * Acquire a new reference to an instance of `PARCInputStream`.
+ *
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] instance The instance of `PARCInputStream` to which to refer.
+ *
+ * @return The same value as the input parameter @p instance
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCInputStream *parcInputStream_Acquire(const PARCInputStream *instance);
+
+/**
+ * Release a `PARCInputStream` reference.
+ *
+ * Only the last invocation where the reference count is decremented to zero,
+ * will actually destroy the `PARCInputStream`.
+ *
+ * @param [in,out] instancePtr is a pointer to the `PARCInputStream` reference.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcInputStream_Release(PARCInputStream **instancePtr);
+#endif // libparc_parc_InputStream_h
diff --git a/libparc/parc/algol/parc_Iterator.c b/libparc/parc/algol/parc_Iterator.c
new file mode 100755
index 00000000..e70a0ff9
--- /dev/null
+++ b/libparc/parc/algol/parc_Iterator.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 <parc/algol/parc_Iterator.h>
+
+struct parc_iterator {
+ PARCObject *object;
+ void *(*init)(PARCObject *);
+ bool (*hasNext)(PARCObject *, void *);
+ void *(*next)(PARCObject *, void *);
+ void (*remove)(PARCObject *, void **);
+ void *(*element)(PARCObject *, void *);
+ void (*fini)(PARCObject *, void *);
+ void (*assertValid)(const void *);
+ bool initialized;
+ void *state;
+};
+
+static void
+_parcIterator_Destroy(PARCIterator **iteratorPtr)
+{
+ PARCIterator *iterator = *iteratorPtr;
+
+ parcObject_Release(&(iterator->object));
+
+ (iterator->fini(iterator->object, iterator->state));
+}
+
+parcObject_ExtendPARCObject(PARCIterator, _parcIterator_Destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static void *
+_parcIterator_Init(PARCIterator *iterator)
+{
+ if (iterator->init) {
+ iterator->state = (iterator->init)(iterator->object);
+ }
+
+ if (iterator->assertValid) {
+ (iterator->assertValid)(iterator->state);
+ }
+
+ iterator->initialized = true;
+ return iterator->state;
+}
+
+static void
+_parcIteratorState_AssertValid(const PARCIterator *iterator)
+{
+ if (iterator->assertValid) {
+ (iterator->assertValid)(iterator->state);
+ }
+}
+
+PARCIterator *
+parcIterator_Create(PARCObject *object,
+ void *(*init)(PARCObject *),
+ bool (*hasNext)(PARCObject *, void *),
+ void *(*next)(PARCObject *, void *),
+ void (*remove)(PARCObject *, void **),
+ void *(*element)(PARCObject *, void *),
+ void (*fini)(PARCObject *, void *),
+ void (*assertValid)(const void *))
+{
+ assertNotNull(object, "PARCObject cannot be NULL.");
+ assertNotNull(init, "'init' function cannot be NULL.");
+ assertNotNull(hasNext, "'hasNext' function cannot be NULL.");
+ assertNotNull(next, "'next' function cannot be NULL.");
+ assertNotNull(element, "'element' function cannot be NULL.");
+ assertNotNull(fini, "'fini' function cannot be NULL.");
+
+ PARCIterator *result = parcObject_CreateInstance(PARCIterator);
+
+ if (result != NULL) {
+ result->object = parcObject_Acquire(object);
+ result->init = init;
+ result->hasNext = hasNext;
+ result->next = next;
+ result->remove = remove;
+ result->element = element;
+ result->fini = fini;
+ result->assertValid = assertValid;
+
+ result->initialized = false;
+ _parcIterator_Init(result);
+ }
+
+ return result;
+}
+
+bool
+parcIterator_IsValid(const PARCIterator *iterator)
+{
+ bool result = false;
+
+ if (iterator != NULL) {
+ if (parcObject_IsValid(iterator)) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+void
+parcIterator_AssertValid(const PARCIterator *iterator)
+{
+ assertTrue(parcIterator_IsValid(iterator), "PARCIterator is not valid.");
+}
+
+parcObject_ImplementAcquire(parcIterator, PARCIterator);
+
+parcObject_ImplementRelease(parcIterator, PARCIterator);
+
+
+void *
+parcIterator_Next(PARCIterator *iterator)
+{
+ parcIterator_OptionalAssertValid(iterator);
+
+ iterator->state = (iterator->next)(iterator->object, iterator->state);
+
+ _parcIteratorState_AssertValid(iterator);
+
+ return (iterator->element)(iterator->object, iterator->state);
+}
+
+bool
+parcIterator_HasNext(const PARCIterator *iterator)
+{
+ parcIterator_OptionalAssertValid(iterator);
+
+ return (iterator->hasNext)(iterator->object, iterator->state);
+}
+
+void
+parcIterator_Remove(PARCIterator *iterator)
+{
+ if (iterator->remove != NULL) {
+ (iterator->remove)(iterator->object, &iterator->state);
+ }
+
+ _parcIteratorState_AssertValid(iterator);
+}
diff --git a/libparc/parc/algol/parc_Iterator.h b/libparc/parc/algol/parc_Iterator.h
new file mode 100644
index 00000000..275a16e7
--- /dev/null
+++ b/libparc/parc/algol/parc_Iterator.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 parc_Iterator.h
+ * @ingroup memory
+ * @brief An iterator over any kind of iteratable collection
+ *
+ * Implementations of a PARCIterator must provide the following functions,
+ * each of which supports the operation of the iterator.
+ * @code
+ * _TYPEIterator * PREFIX_Init(TYPE *object)
+ *
+ * bool PREFIX_Fini(TYPE *map, _TYPEIterator *state)
+ *
+ * _PARCHashMapIterator *PREFIX_Next(PARCHashMap *map, _TYPEIterator *state)
+ *
+ * void PREFIX_Remove(PARCHashMap *map, _TYPEIterator **statePtr )
+ *
+ * bool PREFIX_HasNext(PARCHashMap *map, _TYPEIterator *state)
+ *
+ * PARCObject *PREFIX_Element(PARCHashMap *map, const _TYPEIterator *state)
+ *
+ * PARCObject *PREFIX_Element(TYPE *map, const _TYPEIterator *state)
+ * @endcode
+ *
+ */
+#ifndef libparc_parc_Iterator_h
+#define libparc_parc_Iterator_h
+
+#include <stdbool.h>
+#include <parc/algol/parc_Object.h>
+
+struct parc_iterator;
+typedef struct parc_iterator PARCIterator;
+
+/**
+ * Create a new instance of `PARCIterator`
+ *
+ * Each instance must be provided pointers to functions implementing the iteration primitives for the given PARCObject.
+ *
+ * * `init`
+ * This function is called only when a PARCIterator is created.
+ * The function is expected to initialise and return a pointer to whatever internal state necessary
+ * to provide the subsequent operations.
+ * In subsequent operations of hasNext, next, getElement, and fini, this pointer is provided as a function parameter.
+ *
+ * * `hasNext`
+ * This function returns true if the iteration has more elements.
+ *
+ * * `next`
+ * Returns the next element in the iteration.
+ * If there are no remaining elements in the iteration, then this function must induce a trapOutOfBounds
+ *
+ * * `remove`
+ * Removes the element returned by the `next` function.
+ *
+ * * `getElement`
+ * This function is invoked only from within the `parcIterator_Next` function and
+ * returns the actual iteration value from the current iterator's state.
+ *
+ * * `fini`
+ * This function is called only when the PARCIterator is being destroyed.
+ *
+ * @param [in] object A pointer to the PARCObject that implements the underlying iteration.
+ * @param [in] hasNext A pointer to a function that returns true if there are more elements.
+ * @param [in] next A pointer to a function that returns the next element.
+ * @param [in] remove A pointer to a function that removes the element last returned by the @p next function.
+ * @param [in] getElement A pointer to a function that, given the current position, return the element at the current position.
+ * @param [in] fini A pointer to a function that will be invoked when the PARCIterator is finally deallocated.
+ * @param [in] isValid A pointer to a function that performs validation of the iterator state.
+ *
+ * @return A `PARCIterator`
+ */
+PARCIterator *parcIterator_Create(PARCObject *object,
+ void *(*init)(PARCObject *object),
+ bool (*hasNext)(PARCObject *object, void *state),
+ void *(*next)(PARCObject *object, void *state),
+ void (*remove)(PARCObject *, void **state),
+ void *(*getElement)(PARCObject *object, void *state),
+ void (*fini)(PARCObject *object, void *state),
+ void (*isValid)(const void *));
+
+/**
+ * Determine if an instance of `PARCIterator` 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 `PARCIterator` instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIterator *instance = parcIterator_Create(...);
+ *
+ * if (parcIterator_IsValid(instance)) {
+ * printf("Instance is valid.\n");
+ * }
+ * }
+ * @endcode
+ */
+bool parcIterator_IsValid(const PARCIterator *instance);
+
+/**
+ * Assert that the given `PARCIterator` instance is valid.
+ *
+ * @param [in] iterator A pointer to a valid PARCIterator instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIterator *a = parcIterator_Create(...);
+ *
+ * parcIterator_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcIterator_Release(&b);
+ * }
+ * @endcode
+ */
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcIterator_OptionalAssertValid(_instance_)
+#else
+# define parcIterator_OptionalAssertValid(_instance_) parcIterator_AssertValid(_instance_)
+#endif
+void parcIterator_AssertValid(const PARCIterator *iterator);
+
+/**
+ * Increase the number of references to a `PARCIterator`.
+ *
+ * Note that new `PARCIterator` is not created,
+ * only that the given `PARCIterator` reference count is incremented.
+ * Discard the reference by invoking `parcIterator_Release`.
+ *
+ * @param [in] instance A pointer to a `PARCIterator` instance.
+ *
+ * @return The input `PARCIterator` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIterator *a = parcIterator_Create(...);
+ *
+ * PARCIterator *b = parcIterator_Acquire(a);
+ *
+ * parcIterator_Release(&a);
+ * parcIterator_Release(&b);
+ * }
+ * @endcode
+ */
+PARCIterator *parcIterator_Acquire(const PARCIterator *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] iteratorPtr A pointer to a pointer to the instance to release, which will be set to NULL.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIterator *a = parcIterator_Create(...);
+ *
+ * parcIterator_Release(&a);
+ * }
+ * @endcode
+ */
+void parcIterator_Release(PARCIterator **iteratorPtr);
+
+/**
+ * Return the next item in the iterated list
+ *
+ * @param [in] iterator A pointer to the instance of `PARCIterator`
+ *
+ * @return A pointer to the next item in the iterated list
+ *
+ * Example:
+ * @code
+ * {
+ * while (parcIterator_HasNext(iterator)) {
+ * void *element = parcIterator_Next(iterator);
+ * }
+ * }
+ * @endcode
+ */
+void *parcIterator_Next(PARCIterator *iterator);
+
+/**
+ * Return true if there are more items left over which to iterate.
+ *
+ * @param [in] iterator A pointer to the instance of `PARCIterator`
+ *
+ * @return True if there is are more items over which to iterate; false otherwise.
+ *
+ * Example:
+ * @code
+ * {
+ * while (parcIterator_HasNext(iterator)) {
+ * void *element = parcIterator_Next(iterator);
+ * }
+ * }
+ * @endcode
+ */
+bool parcIterator_HasNext(const PARCIterator *iterator);
+
+/**
+ * Removes from the underlying collection the last element returned by the iterator (optional operation).
+ * This function can be called only once per call to `parcIterator_Next`.
+ * The behavior of an iterator is unspecified if the underlying collection is
+ * modified while the iteration is in progress in any way other than by calling this method.
+ *
+ * Pointers to the element after removing it via this function may point to invalid remnants of the object.
+ * To avoid this, acquire a reference to the element before invoking this function.
+ *
+ * @param [in] iterator A pointer to the instance of `PARCIterator`
+ *
+ * Example:
+ * @code
+ * {
+ * while (parcIterator_HasNext(iterator)) {
+ * void *element = parcIterator_Next(iterator);
+ * }
+ * }
+ * @endcode
+ */
+void parcIterator_Remove(PARCIterator *iterator);
+#endif // libparc_parc_Iterator_h
diff --git a/libparc/parc/algol/parc_JSON.c b/libparc/parc/algol/parc_JSON.c
new file mode 100755
index 00000000..d70a302e
--- /dev/null
+++ b/libparc/parc/algol/parc_JSON.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <ctype.h>
+#include <math.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_JSONPair.h>
+#include <parc/algol/parc_JSONValue.h>
+#include <parc/algol/parc_JSONParser.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_PathName.h>
+
+struct parc_json {
+ PARCList *members;
+};
+
+static void
+_destroyPARCJSON(PARCJSON **jsonPtr)
+{
+ PARCJSON *json = *jsonPtr;
+
+ parcList_Release(&json->members);
+}
+
+parcObject_ExtendPARCObject(PARCJSON, _destroyPARCJSON, NULL, parcJSON_ToString, parcJSON_Equals, NULL, NULL, NULL);
+
+PARCJSON *
+parcJSON_Create(void)
+{
+ PARCJSON *result = parcObject_CreateInstance(PARCJSON);
+ if (result != NULL) {
+ result->members = parcList(parcArrayList_Create((void (*)(void **))parcJSONPair_Release), PARCArrayListAsPARCList);
+ }
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcJSON, PARCJSON);
+
+parcObject_ImplementRelease(parcJSON, PARCJSON);
+
+static bool
+_memberListEquals(const PARCList *x, const PARCList *y)
+{
+ for (size_t i = 0; i < parcList_Size(x); i++) {
+ PARCJSONPair *pairA = parcList_GetAtIndex(x, i);
+ PARCJSONPair *pairB = parcList_GetAtIndex(y, i);
+ if (parcJSONPair_Equals(pairA, pairB) == false) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static PARCBuffer *
+_toCreatedBuffer(const PARCJSON *json, bool compact)
+{
+ if (json == NULL) {
+ return NULL;
+ }
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcJSON_BuildString(json, composer, compact);
+
+ PARCBuffer *result = parcBufferComposer_ProduceBuffer(composer);
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+static char *
+_toString(const PARCJSON *json, bool compact)
+{
+ PARCBuffer *tempBuffer = _toCreatedBuffer(json, compact);
+
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ return result;
+}
+
+bool
+parcJSON_Equals(const PARCJSON *x, const PARCJSON *y)
+{
+ bool result = false;
+
+ if (x == NULL && y == NULL) {
+ result = true;
+ } else if (x != NULL && y != NULL) {
+ if (parcList_Size(x->members) == parcList_Size(y->members)) {
+ if (_memberListEquals(x->members, y->members)) {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcJSON_Copy(const PARCJSON *src)
+{
+ //TODO - This is an ineffecient deep copy. The _Copy() operation needs to be implementd for all PARCJSON* types
+ //before we can do an effecient deep copy.
+ if (src == NULL) {
+ return NULL;
+ }
+ PARCBuffer *temp = _toCreatedBuffer(src, true);
+ PARCJSON *result = parcJSON_ParseBuffer(temp);
+ parcBuffer_Release(&temp);
+
+ return result;
+}
+
+
+PARCHashCode
+parcJSON_HashCode(const PARCJSON *json)
+{
+ PARCBuffer *temp = _toCreatedBuffer(json, true);
+ PARCHashCode result = parcBuffer_HashCode(temp);
+ parcBuffer_Release(&temp);
+
+ return result;
+}
+
+void
+parcJSON_Display(const PARCJSON *json, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCJSON@%p {", json);
+ for (size_t index = 0; index < parcList_Size(json->members); index++) {
+ PARCJSONPair *pair = parcList_GetAtIndex(json->members, index);
+ parcJSONPair_Display(pair, indentation + 1);
+ }
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+PARCJSONPair *
+parcJSON_GetPairByIndex(const PARCJSON *json, size_t index)
+{
+ PARCJSONPair *result = NULL;
+
+ if (parcList_Size(json->members) > index) {
+ result = parcList_GetAtIndex(json->members, index);
+ }
+
+ return result;
+}
+
+PARCJSONValue *
+parcJSON_GetValueByIndex(const PARCJSON *json, size_t index)
+{
+ PARCJSONValue *result = NULL;
+
+ if (parcList_Size(json->members) > index) {
+ result = parcJSONPair_GetValue(parcList_GetAtIndex(json->members, index));
+ }
+
+ return result;
+}
+
+const PARCJSONPair *
+parcJSON_GetPairByName(const PARCJSON *json, const char *name)
+{
+ PARCJSONPair *result = NULL;
+
+ PARCBuffer *nameBuffer = parcBuffer_Wrap((uint8_t *) name, strlen(name), 0, strlen(name));
+ for (size_t index = 0; index < parcList_Size(json->members); index++) {
+ PARCJSONPair *pair = parcList_GetAtIndex(json->members, index);
+ if (parcBuffer_Equals(nameBuffer, parcJSONPair_GetName(pair))) {
+ result = pair;
+ break;
+ }
+ }
+ parcBuffer_Release(&nameBuffer);
+ return result;
+}
+
+PARCJSONValue *
+parcJSON_GetValueByName(const PARCJSON *json, const char *name)
+{
+ PARCJSONValue *result = NULL;
+ const PARCJSONPair *pair = parcJSON_GetPairByName(json, name);
+ if (pair != NULL) {
+ result = parcJSONPair_GetValue(pair);
+ }
+
+ return result;
+}
+
+PARCList *
+parcJSON_GetMembers(const PARCJSON *json)
+{
+ return json->members;
+}
+
+PARCBufferComposer *
+parcJSON_BuildString(const PARCJSON *json, PARCBufferComposer *composer, bool compact)
+{
+ parcBufferComposer_PutChar(composer, '{');
+ if (!compact) {
+ parcBufferComposer_PutChar(composer, ' ');
+ }
+
+ char *separator = "";
+ for (size_t i = 0; i < parcList_Size(json->members); i++) {
+ parcBufferComposer_PutString(composer, separator);
+ parcJSONPair_BuildString(parcList_GetAtIndex(json->members, i), composer, compact);
+ separator = ", ";
+ if (compact) {
+ separator = ",";
+ }
+ }
+
+ if (!compact) {
+ parcBufferComposer_PutChar(composer, ' ');
+ }
+ parcBufferComposer_PutChar(composer, '}');
+ return composer;
+}
+
+
+char *
+parcJSON_ToString(const PARCJSON *json)
+{
+ return _toString(json, false);
+}
+
+char *
+parcJSON_ToCompactString(const PARCJSON *json)
+{
+ return _toString(json, true);
+}
+
+const PARCJSONValue *
+parcJSON_GetByPathName(const PARCJSONValue *pathNode, const PARCPathName *path)
+{
+ for (int i = 0; i < parcPathName_Size(path); i++) {
+ char *name = parcPathName_GetAtIndex(path, i);
+ if (parcJSONValue_IsJSON(pathNode)) {
+ const PARCJSONPair *pair = parcJSON_GetPairByName(parcJSONValue_GetJSON(pathNode), name);
+ if (pair == NULL) {
+ pathNode = NULL;
+ break;
+ }
+ pathNode = parcJSONPair_GetValue(pair);
+ } else if (parcJSONValue_IsArray(pathNode)) {
+ size_t index = strtoll(name, NULL, 10);
+ if (index > parcJSONArray_GetLength(parcJSONValue_GetArray(pathNode))) {
+ pathNode = NULL;
+ break;
+ }
+ pathNode = parcJSONArray_GetValue(parcJSONValue_GetArray(pathNode), index);
+ } else {
+ pathNode = NULL;
+ break;
+ }
+ }
+
+ return pathNode;
+}
+
+const PARCJSONValue *
+parcJSON_GetByPath(const PARCJSON *json, const char *path)
+{
+ PARCJSONValue *pathNode = parcJSONValue_CreateFromJSON((PARCJSON *) json);
+
+ PARCPathName *pathName = parcPathName_Parse(path);
+ const PARCJSONValue *result = parcJSON_GetByPathName(pathNode, pathName);
+ parcPathName_Release(&pathName);
+
+ parcJSONValue_Release(&pathNode);
+ return result;
+}
+
+PARCJSON *
+parcJSON_ParseString(const char *string)
+{
+ // The input string is read-only, therefore we can cast it here when calling the parcBuffer_WrapCString()
+ // to work around the fact that the function does not take a 'const' attribute.
+ // This function is not going to modify the input string, so the 'const' promise will be kept.
+ PARCBuffer *buffer = parcBuffer_WrapCString((char *) string);
+
+ PARCJSON *result = parcJSON_ParseBuffer(buffer);
+ parcBuffer_Release(&buffer);
+
+ return result;
+}
+
+PARCJSON *
+parcJSON_ParseBuffer(PARCBuffer *buffer)
+{
+ PARCJSON *result = NULL;
+
+ // The input string is read-only, therefore we can cast it here when calling the parcBuffer_WrapCString()
+ // to work around the fact that the function does not take a 'const' attribute.
+ // This function is not going to modify the input string, so the 'const' promise will be kept.
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+
+ char firstCharacter = parcJSONParser_PeekNextChar(parser);
+ if (firstCharacter == '{') {
+ PARCJSONValue *value = parcJSONValue_ObjectParser(parser);
+
+ result = parcJSON_Acquire(parcJSONValue_GetJSON(value));
+ parcJSONValue_Release(&value);
+ }
+
+ parcJSONParser_Release(&parser);
+
+ return result;
+}
+
+PARCJSON *
+parcJSON_AddPair(PARCJSON *json, PARCJSONPair *pair)
+{
+ parcList_Add(json->members, parcJSONPair_Acquire(pair));
+ return json;
+}
+
+PARCJSON *
+parcJSON_AddValue(PARCJSON *json, const char *name, PARCJSONValue *value)
+{
+ PARCJSONPair *pair = parcJSONPair_CreateFromJSONValue(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+
+ return json;
+}
+
+PARCJSON *
+parcJSON_AddString(PARCJSON *json, const char *name, const char *value)
+{
+ PARCJSONPair *pair = parcJSONPair_CreateFromString(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+
+ return json;
+}
+
+PARCJSON *
+parcJSON_AddObject(PARCJSON *json, const char *name, PARCJSON *value)
+{
+ PARCJSONPair *pair = parcJSONPair_CreateFromJSON(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+
+ return json;
+}
+
+PARCJSON *
+parcJSON_AddInteger(PARCJSON *json, const char *name, int64_t value)
+{
+ PARCJSONPair *pair = parcJSONPair_CreateFromInteger(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+
+ return json;
+}
+
+PARCJSON *
+parcJSON_AddBoolean(PARCJSON *json, const char *name, bool value)
+{
+ PARCJSONPair *pair = parcJSONPair_CreateFromBoolean(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+
+ return json;
+}
+
+PARCJSON *
+parcJSON_AddArray(PARCJSON *json, const char *name, PARCJSONArray *value)
+{
+ PARCJSONPair *pair = parcJSONPair_CreateFromJSONArray(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+
+ return json;
+}
diff --git a/libparc/parc/algol/parc_JSON.h b/libparc/parc/algol/parc_JSON.h
new file mode 100755
index 00000000..dc8996ca
--- /dev/null
+++ b/libparc/parc/algol/parc_JSON.h
@@ -0,0 +1,658 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_JSON.h
+ * @ingroup inputoutput
+ * @brief A complete JSON encoding and decoding library.
+ *
+ * # Parsing #
+ * Parse a null-terminated C string containing JSON via {@link parcJSON_ParseString}.
+ *
+ * # Printing #
+ * Print a JSON object via {@link parcJSON_ToString}.
+ *
+ * # Composing #
+ * Compose JSON objects via {@link parcJSON_Create} and add members via {@link parcJSON_Add}.
+ * Compose members as JSON Pairs consisting of a name and value. See functions named `parcJSONPair_Create*`
+ *
+ */
+#ifndef libparc_parc_JSON_h
+#define libparc_parc_JSON_h
+
+#include <stdbool.h>
+
+struct parc_json;
+typedef struct parc_json PARCJSON;
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_PathName.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_JSONPair.h>
+#include <parc/algol/parc_JSONValue.h>
+
+/**
+ * Create a new JSON object.
+ *
+ * The JSON new object contains no members.
+ *
+ * @return A pointer to a `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_Create();
+ * ...
+ * parcJSONValue_Release(&json);
+ * }
+ * @endcode
+ *
+ * @see {@link parcJSON_Add}
+ */
+PARCJSON *parcJSON_Create(void);
+
+/**
+ * Create a deep copy of a JSON object. Call parcJSON_Release to free the object when done with it.
+ *
+ * @return A pointer to a `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *jsonSrc = parcJSON_Create();
+ * ...
+ * PARCJSON *jsonCopy = parcJSON_Copy(jsonSrc);
+ * ...
+ * parcJSONValue_Release(&jsonSrc);
+ * ...
+ * parcJSONValue_Release(&jsonCopy);
+ * }
+ * @endcode
+ *
+ */
+PARCJSON *parcJSON_Copy(const PARCJSON *src);
+
+/**
+ * Increase the number of references to a `PARCJSON` instance.
+ *
+ * Note that a new `PARCJSON` is not created,
+ * only that the given `PARCJSON` reference count is incremented.
+ * Discard the reference by invoking {@link parcJSON_Release}.
+ *
+ * @param [in] json A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *x = parcJSON_Create();
+ *
+ * PARCJSON *x2 = parcJSON_Acquire(x);
+ *
+ * parcJSON_Release(&x);
+ * parcJSON_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see {@link parcJSON_Release}
+ */
+PARCJSON *parcJSON_Acquire(const PARCJSON *json);
+
+/**
+ * Determine if two `PARCJSON` instances are equal.
+ *
+ * Two `PARCJSON` instances are equal if, and only if,
+ * they contain the equal members, in the same order.
+ *
+ * The following equivalence relations on non-null `PARCJSON` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcJSON_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcJSON_Equals(x, y)` must return true if and only if
+ * `parcJSON_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcJSON_Equals(x, y)` returns true and
+ * `parcJSON_Equals(y, z)` returns true,
+ * then `parcJSON_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcJSON_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcJSON_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] x A pointer to a `PARCJSON` instance.
+ * @param [in] y A pointer to a `PARCJSON` instance.
+ * @return true if the two `PARCJSON` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *a = parcJSON_Create();
+ * PARCJSON *b = parcJSON_Create();
+ *
+ * if (parcJSON_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool parcJSON_Equals(const PARCJSON *x, const PARCJSON *y);
+
+/**
+ * Add a JSON Pair to the members of a JSON Object.
+ *
+ * @param [in,out] json A pointer to a `PARCJSON` instance.
+ * @param [in] pair A pointer to a `PARCJSONPair` instance.
+ *
+ * @return The pointer to the `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_Create();
+ *
+ * PARCJSONPair *pair = parcJSONPair_CreateFromInteger("pi", 314159);
+ * parcJSON_AddPair(json, pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSON *parcJSON_AddPair(PARCJSON *json, PARCJSONPair *pair);
+
+/**
+ * Pretty print the given `PARCJSON` instance.
+ *
+ * @param [in] json The `PARCJSON` instance to be printed.
+ * @param [in] indentation The amount of indentation to prefix each line of output
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+ * parcJSON_Display(json, 0);
+ * }
+ * @endcode
+ */
+void parcJSON_Display(const PARCJSON *json, int indentation);
+
+/**
+ * Get the list of members of the given `PARCJSON` instance.
+ *
+ * A new reference to the {@link PARCList} is not created.
+ * The caller must create a new reference, if it retains a reference to the buffer.
+ *
+ * @param [in] json A pointer to a `PARCJSON` instance.
+ * @return A pointer to a `PARCList` instance containing the members.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+ * PARCList *members = parcJSON_GetMembers(json);
+ * }
+ * @endcode
+ */
+PARCList *parcJSON_GetMembers(const PARCJSON *json);
+
+/**
+ * Get the PARCJSONPair at the index in the given `PARCJSON` instance.
+ *
+ * @param [in] json A pointer to a `PARCJSON` instance.
+ * @param [in] index The index value of the desired element.
+ * @return A pointer to a `PARCJSONPair` instance containing or NULL if there is nothing at the specified index.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+ * PARCJSONPair *pair = parcJSON_GetPairByIndex(json, 0);
+ * }
+ * @endcode
+ */
+PARCJSONPair *parcJSON_GetPairByIndex(const PARCJSON *json, size_t index);
+
+/**
+ * Get the PARCJSONValue at the index in the given `PARCJSON` instance.
+ *
+ * @param [in] json A pointer to a `PARCJSON` instance.
+ * @param [in] index The index value of the desired element.
+ * @return A pointer to a `PARCJSONValue` instance containing or NULL if there is nothing at the specified index.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+ * PARCJSONValue *pair = parcJSON_GetValueByIndex(json, 0);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSON_GetValueByIndex(const PARCJSON *json, size_t index);
+
+/**
+ * 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] jsonPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_Create();
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ */
+void parcJSON_Release(PARCJSON **jsonPtr);
+
+/**
+ * Parse a null-terminated C string into a `PARCJSON` instance.
+ *
+ * Only 8-bit characters are parsed.
+ *
+ * @param [in] string A null-terminated C string containing a well-formed JSON object.
+ *
+ * @return A pointer to a `PARCJSON` instance with one reference, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"key\" : 1, \"array\" : [1, 2, 3] }");
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_ParseString(const char *string);
+
+/**
+ * Parse a null-terminated C string into a `PARCJSON` instance.
+ *
+ * Only 8-bit characters are parsed.
+ *
+ * @param [in] buffer A pointer to a valid PARCBuffer instance.
+ *
+ * @return A pointer to a `PARCJSON` instance with one reference, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufer *buffer = parcBuffer_WrapCString("{ \"key\" : 1, \"array\" : [1, 2, 3] }");
+ * PARCJSON *json = parcJSON_ParseBuffer(buffer);
+ *
+ * parcBuffer_Release(&buffer);
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_ParseBuffer(PARCBuffer *buffer);
+
+/**
+ * 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] json A pointer to the `PARCJSON` 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
+ * {
+ * PARCJSON *json = parcJSON_Create();
+ *
+ * char *string = parcJSON_ToString(json);
+ *
+ * if (string != NULL) {
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ *
+ * @see {@link parcJSONPair_BuildString}
+ * @see {@link parcJSONPair_Display}
+ */
+char *parcJSON_ToString(const PARCJSON *json);
+
+/**
+ * Produce a null-terminated compact (minimally escaped and formated) string representation of the specified instance.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] json A pointer to the `PARCJSON` 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
+ * {
+ * PARCJSON *json = parcJSON_Create();
+ *
+ * char *string = parcJSON_ToCompactString(json);
+ *
+ * if (string != NULL) {
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ *
+ * @see {@link parcJSONPair_BuildString}
+ * @see {@link parcJSONPair_Display}
+ */
+char *parcJSON_ToCompactString(const PARCJSON *json);
+
+/**
+ * Produce a PARCHashCode for the JSON object.
+ *
+ * @param [in] json A pointer to the `PARCJSON` instance.
+ *
+ * @return PARCHashCode The object's hash-code.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_Create();
+ * ...
+ * PARCHashCode hashCode = parcJSON_HashCode(json);
+ * ....
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ *
+ */
+PARCHashCode parcJSON_HashCode(const PARCJSON *json);
+
+/**
+ * Get the {@link PARCJSONPair} with the given key name.
+ *
+ * @param [in] json A pointer to a `PARCJSON` instance.
+ * @param [in] name A null-terminated C string containing the name of the pair to return.
+ *
+ * @return A pointer to the named `PARCJSONPair`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"key\" : 1, "array" : [1, 2, 3] }");
+ *
+ * PARCJSONPair *arrayPair = parcJSON_GetPairByName(json, "array");
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ *
+ * @see parcJSON_Add
+ */
+const PARCJSONPair *parcJSON_GetPairByName(const PARCJSON *json, const char *name);
+
+/**
+ * Get the {@link PARCJSONValue} with the given key name.
+ *
+ * @param [in] json A pointer to a `PARCJSON` instance.
+ * @param [in] name A null-terminated C string containing the name of the pair to return.
+ *
+ * @return A pointer to the named `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"key\" : 1, "array" : [1, 2, 3] }");
+ *
+ * PARCJSONValue *arrayValue = parcJSON_GetValueByName(json, "array");
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ *
+ * @see parcJSON_Add
+ */
+PARCJSONValue *parcJSON_GetValueByName(const PARCJSON *json, const char *name);
+
+/**
+ * Get the JSON pair named by the given '/' separated path name.
+ *
+ * Using a '/' separated list of JSON pair names, return the {@link PARCJSONPair} named by the path.
+ * This function currently returns the Value, not the Pair specified by the `PARCPathName`
+ *
+ * @param [in] json A pointer to a `PARCJSON` instance.
+ * @param [in] path A pointer to a null-terminated C string containing the full path of the `PARCJSONPair`.
+ *
+ * @return A pointer to the {@link PARCJSONValue} named by the path.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"key\" : 1, "array" : [1, 2, 3] }");
+ *
+ * PARCJSONValue *key = parcJSON_GetByPath(json, "/key");
+ *
+ * PARCJSONValue *array_1 = parcJSON_GetByPath(json, "/array/1");
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ */
+const PARCJSONValue *parcJSON_GetByPath(const PARCJSON *json, const char *path);
+
+/**
+ * Get the JSON pair named by the given {@link PARCPathName}.
+ * This function currently returns the Value, not the Pair specified by the `PARCPathName`
+ *
+ * @param [in] pathNode A pointer to a {@link PARCJSONValue} instance.
+ * @param [in] pathName A pointer to valid `PARCPathName` instance.
+ *
+ * @return A pointer to the `PARCJSONValue` named by the path.
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_ParseString("{ \"key\" : 1, "array" : [1, 2, 3] }");
+ *
+ * PARCPathName *keyPath = parcPathName_Create("/key");
+ * PARCPathName *array1Path = parcPathName_Create("/array/1");
+ *
+ * PARCJSONValue *key = parcJSON_GetByPathName(json, keyPath);
+ *
+ * PARCJSONValue *array_1 = parcJSON_GetByPathName(json, array1Path);
+ *
+ * parcJSON_Release(&json);
+ * }
+ * @endcode
+ */
+const PARCJSONValue *parcJSON_GetByPathName(const PARCJSONValue *pathNode, const PARCPathName *pathName);
+
+/**
+ * Append a representation of the specified {@link PARCJSON} instance to the given {@link PARCBufferComposer}.
+ *
+ * @param [in] json A pointer to the `PARCJSON` instance.
+ * @param [in,out] composer A `PARCBufferComposer` to append to this URI segment.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The given `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * parcJSON_BuildString(instance, result);
+ *
+ * PARCBuffer *string = parcBufferComposer_FinalizeBuffer(result);
+ * printf("JSON String: %s\n", parcBuffer_ToString(string));
+ * parcBuffer_Release(&string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcJSON_BuildString(const PARCJSON *json, PARCBufferComposer *composer, bool compact);
+
+/**
+ * Create and add a JSON string pair to a PARCJSON object.
+ *
+ * @param [in] json A pointer to a valid `PARCJSON` instance.
+ * @param [in] name A pointer to a nul-terminated C string containing the name of the pair.
+ * @param [in] value A pointer to a nul-terminated C string containing the value.
+ *
+ * @return A pointer to the updated `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_AddString(PARCJSON *json, const char *name, const char *value);
+
+/**
+ * Create and add a JSON object pair to a PARCJSON object.
+ *
+ * @param [in] json A pointer to a valid `PARCJSON` instance.
+ * @param [in] name A pointer to a nul-terminated C string containing the name of the pair.
+ * @param [in] value A pointer to a valid `PARCJON` value.
+ *
+ * @return A pointer to the updated `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_AddObject(PARCJSON *json, const char *name, PARCJSON *value);
+
+/**
+ * Create and add a pair with an array for the value to a PARCJSON object.
+ *
+ * @param [in] json A pointer to a valid `PARCJSON` instance.
+ * @param [in] name A pointer to a nul-terminated C string containing the name of the pair.
+ * @param [in] array A pointer to a valid `PARCJONArray` value.
+ *
+ * @return A pointer to the updated `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_AddArray(PARCJSON *json, const char *name, PARCJSONArray *array);
+
+/**
+ * Create and add a pair with a PARCJSONValue for the value to a PARCJSON object.
+ *
+ * @param [in] json A pointer to a valid `PARCJSON` instance.
+ * @param [in] name A pointer to a nul-terminated C string containing the name of the pair.
+ * @param [in] value A pointer to a valid `PARCJONValue` value.
+ *
+ * @return A pointer to the updated `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_AddValue(PARCJSON *json, const char *name, PARCJSONValue *value);
+
+/**
+ * Create and add an integer pair to a PARCJSON object.
+ *
+ * @param [in] json A pointer to a valid `PARCJSON` instance.
+ * @param [in] name A pointer to a nul-terminated C string containing the name of the pair.
+ * @param [in] value An integer value.
+ *
+ * @return A pointer to the updated `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_AddInteger(PARCJSON *json, const char *name, int64_t value);
+
+/**
+ * Create and add a boolean pair to a PARCJSON object.
+ *
+ * @param [in] json A pointer to a valid `PARCJSON` instance.
+ * @param [in] name A pointer to a nul-terminated C string containing the name of the pair.
+ * @param [in] value An boolean value.
+ *
+ * @return A pointer to the updated `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_AddBoolean(PARCJSON *json, const char *name, bool value);
+
+/**
+ * Create and add a boolean pair to a PARCJSON object.
+ *
+ * @param [in] json A pointer to a valid `PARCJSON` instance.
+ * @param [in] name A pointer to a nul-terminated C string containing the name of the pair.
+ * @param [in] value An boolean value.
+ *
+ * @return A pointer to the updated `PARCJSON` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCJSON *parcJSON_AddArray(PARCJSON *json, const char *name, PARCJSONArray *value);
+#endif // libparc_parc_JSON_h
diff --git a/libparc/parc/algol/parc_JSONArray.c b/libparc/parc/algol/parc_JSONArray.c
new file mode 100755
index 00000000..87421e12
--- /dev/null
+++ b/libparc/parc/algol/parc_JSONArray.c
@@ -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.
+ */
+
+/**
+ */
+
+#include <config.h>
+
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_JSONArray.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Deque.h>
+#include <parc/algol/parc_JSONValue.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+struct parcJSONArray {
+ PARCDeque *array;
+};
+
+static void
+_destroy(PARCJSONArray **arrayPtr)
+{
+ PARCJSONArray *array = *arrayPtr;
+ // Un-reference the JSONValue instances here because parcDeque doesn't (yet) acquire and release its own references.
+
+ for (int i = 0; i < parcDeque_Size(array->array); i++) {
+ PARCJSONValue *value = parcDeque_GetAtIndex(array->array, i);
+ parcJSONValue_Release(&value);
+ }
+ parcDeque_Release(&array->array);
+}
+
+parcObject_ExtendPARCObject(PARCJSONArray, _destroy, NULL, parcJSONArray_ToString, parcJSONArray_Equals, NULL, NULL, NULL);
+
+static const PARCObjectDescriptor parcArrayValue_ObjInterface = {
+ .destroy = (PARCObjectDestroy *) parcJSONValue_Release,
+ .toString = (PARCObjectToString *) parcJSONValue_ToString,
+ .equals = (PARCObjectEquals *) parcJSONValue_Equals
+};
+
+void
+parcJSONArray_AssertValid(const PARCJSONArray *array)
+{
+ assertNotNull(array, "Must be a non-null pointer to a PARCJSONArray instance.");
+ assertNotNull(array->array, "Must be a non-null pointer to a PARCDeque instance.");
+}
+
+PARCJSONArray *
+parcJSONArray_Create(void)
+{
+ PARCJSONArray *result = parcObject_CreateInstance(PARCJSONArray);
+ result->array = parcDeque_CreateObjectInterface(&parcArrayValue_ObjInterface);
+ return result;
+}
+
+parcObject_ImplementAcquire(parcJSONArray, PARCJSONArray);
+
+parcObject_ImplementRelease(parcJSONArray, PARCJSONArray);
+
+bool
+parcJSONArray_Equals(const PARCJSONArray *x, const PARCJSONArray *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ result = parcDeque_Equals(x->array, y->array);
+ }
+ return result;
+}
+
+PARCJSONArray *
+parcJSONArray_AddValue(PARCJSONArray *array, PARCJSONValue *value)
+{
+ parcDeque_Append(array->array, parcJSONValue_Acquire(value));
+ return array;
+}
+
+size_t
+parcJSONArray_GetLength(const PARCJSONArray *array)
+{
+ return parcDeque_Size(array->array);
+}
+
+PARCJSONValue *
+parcJSONArray_GetValue(const PARCJSONArray *array, size_t index)
+{
+ return (PARCJSONValue *) parcDeque_GetAtIndex(array->array, index);
+}
+
+PARCBufferComposer *
+parcJSONArray_BuildString(const PARCJSONArray *array, PARCBufferComposer *composer, bool compact)
+{
+#ifdef hasPARCIterator
+ PARCIterator *iterator = parcDeque_GetIterator(array->array);
+
+ parcBufferComposer_PutChar(composer, '[');
+
+ char *separator = "";
+
+ for (i = parcIterator_Start(); i < parcIterator_Limit(iterator); i = parcIterator_Next(iterator)) {
+ PARCJSONValue *value = parcIterator_Get(iterator);
+ parcBufferComposer_PutString(composer, separator);
+ separator = ", ";
+ if (compact) {
+ separator = ",";
+ }
+
+ parcJSONValue_BuildString(value, composer);
+ }
+ parcBufferComposer_PutChar(composer, ']');
+#else
+ parcBufferComposer_PutChar(composer, '[');
+ if (!compact) {
+ parcBufferComposer_PutChar(composer, ' ');
+ }
+
+ char *separator = "";
+
+ for (int i = 0; i < parcDeque_Size(array->array); i++) {
+ PARCJSONValue *value = parcDeque_GetAtIndex(array->array, i);
+ parcBufferComposer_PutString(composer, separator);
+
+ parcJSONValue_BuildString(value, composer, compact);
+ separator = ", ";
+ if (compact) {
+ separator = ",";
+ }
+ }
+ if (!compact) {
+ parcBufferComposer_PutChar(composer, ' ');
+ }
+ parcBufferComposer_PutChar(composer, ']');
+#endif
+ return composer;
+}
+
+void
+parcJSONArray_Display(const PARCJSONArray *array, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCJSONArray@%p {", array);
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+static char *
+_parcJSONArray_ToString(const PARCJSONArray *array, bool compact)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ parcJSONArray_BuildString(array, composer, compact);
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+char *
+parcJSONArray_ToString(const PARCJSONArray *array)
+{
+ return _parcJSONArray_ToString(array, false);
+}
+
+char *
+parcJSONArray_ToCompactString(const PARCJSONArray *array)
+{
+ return _parcJSONArray_ToString(array, true);
+}
diff --git a/libparc/parc/algol/parc_JSONArray.h b/libparc/parc/algol/parc_JSONArray.h
new file mode 100755
index 00000000..32fa9817
--- /dev/null
+++ b/libparc/parc/algol/parc_JSONArray.h
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_JSONArray.h
+ * @brief A JSON Array stores an array of JSON objects.
+ * @ingroup inputoutput
+ *
+ */
+#ifndef libparc_parc_JSONArray_h
+#define libparc_parc_JSONArray_h
+
+struct parcJSONArray;
+typedef struct parcJSONArray PARCJSONArray;
+
+#include <parc/algol/parc_JSONValue.h>
+
+/**
+ * Create an empty `PARCJSONArray` instance.
+ *
+ * @return A pointer to an empty `PARCJSONArray` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *x = parcJSONArray_Create();
+ * parcJSONArray_Release(&x);
+ * }
+ * @endcode
+ *
+ * @see parcJSONArray_AddValue
+ */
+PARCJSONArray *parcJSONArray_Create(void);
+
+/**
+ * Increase the number of references to a `PARCJSONArray`.
+ *
+ * Note that new `PARCJSONArray` is not created,
+ * only that the given `PARCJSONArray` reference count is incremented.
+ * Discard the reference by invoking {@link parcJSONArray_Release}.
+ *
+ * @param [in] array A pointer to a `PARCJSONArray` instance.
+ *
+ * @return The input `PARCJSONArray` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *x = parcJSONArray_Create();
+ *
+ * PARCJSONArray *x_2 = parcJSONArray_Acquire(x);
+ *
+ * parcJSONArray_Release(&x);
+ * parcJSONArray_Release(&x_2);
+ * }
+ * @endcode
+ */
+PARCJSONArray *parcJSONArray_Acquire(const PARCJSONArray *array);
+
+/**
+ * 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] arrayPtr A pointer to a pointer to the instance of `PARCJSONArray` to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *x = parcJSONArray_Create();
+ *
+ * parcJSONArray_Release(&x);
+ * }
+ * @endcode
+ */
+void parcJSONArray_Release(PARCJSONArray **arrayPtr);
+
+/**
+ * Assert that an instance of `PARCJSONArray` 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] array A pointer to a `PARCJSONArray` instance.
+ */
+void parcJSONArray_AssertValid(const PARCJSONArray *array);
+
+/**
+ * Determine if two `PARCJSONArray` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCJSONArray` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcJSONArray_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcJSONArray_Equals(x, y)` must return true if and only if
+ * `parcJSONArray_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcJSONArray_Equals(x, y)` returns true and
+ * `parcJSONArray_Equals(y, z)` returns true,
+ * then `parcJSONArray_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcJSONArray_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcJSONArray_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a `PARCJSONArray` instance.
+ * @param [in] y A pointer to a `PARCJSONArray` instance.
+ *
+ * @return true `PARCJSONArray` x and y are equal.
+ * @return false `PARCJSONArray` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *x = parcJSONArray_Create();
+ * PARCJSONArray *y = parcJSONArray_Create();
+ *
+ * if (parcJSONArray_Equals(x, y)) {
+ * printf("Arrays are equal.\n");
+ * } else {
+ * printf("Arrays are NOT equal.\n");
+ * }
+ *
+ * parcJSONArray_Release(&x);
+ * parcJSONArray_Release(&y);
+ * }
+ * @endcode
+ */
+bool parcJSONArray_Equals(const PARCJSONArray *x, const PARCJSONArray *y);
+
+/**
+ * Add {@link PARCJSONValue} instance to the given `PARCJSONArray`.
+ *
+ * A new reference to the `PARCJSONValue` is acquired by this call.
+ *
+ * @param [in,out] array A pointer to a `PARCJSONArray` instance.
+ * @param [in] value A pointer to a `PARCJSONValue` instance.
+ *
+ * @return A pointer to the @p array.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *array = parcJSONArray_Create();
+ *
+ * PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415);
+ * parcJSONArray_AddValue(array, value);
+ * parcJSONValue_Release(&value);
+ *
+ * parcJSONArray_Release(&array);
+ * }
+ * @endcode
+ *
+ */
+PARCJSONArray *parcJSONArray_AddValue(PARCJSONArray *array, PARCJSONValue *value);
+
+/**
+ * Get the length of the given `PARCJSONArray` instance.
+ *
+ * @param [in] array A pointer to a `PARCJSONArray` instance.
+ *
+ * @return The number of elements in the array.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *array = parcJSONArray_Create();
+ *
+ * PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415);
+ * parcJSONArray_AddValue(array, value);
+ * parcJSONValue_Release(&value);
+ *
+ * parcJSONValue_GetLength(array);
+ *
+ * parcJSONArray_Release(&array);
+ * }
+ * @endcode
+ */
+size_t parcJSONArray_GetLength(const PARCJSONArray *array);
+
+/**
+ * Get the {@link PARCJSONValue} stored at the given index in the `PARCJSONArray`.
+ * A new reference is not acquired.
+ * The caller must acquire its own reference if needed.
+ *
+ * @param [in] array A pointer to a `PARCJSONArray` instance.
+ * @param [in] index The index of the `PARCJSONValue` to get.
+ *
+ * @return The pointer to the requested `PARCJSONValue`, or NULL if the index exceeded the length of the array.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *array = parcJSONArray_Create();
+ *
+ * PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415);
+ * parcJSONArray_AddValue(array, value);
+ * parcJSONValue_Release(&value);
+ *
+ * PARCJSONValue *actualValue = parcJSONValue_GetValue(array, 0);
+ *
+ * parcJSONArray_Release(&array);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONArray_GetValue(const PARCJSONArray *array, size_t index);
+
+/**
+ * Append a representation of the specified `PARCJSONArray` instance to the given
+ * {@link PARCBufferComposer}.
+ *
+ * @param [in] array A pointer to the `PARCJSONArray` instance.
+ * @param [in,out] composer A pointer to the `PARCBufferComposer` instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The given `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * parcJSONArray_BuildString(instance, result);
+ *
+ * PARCBuffer *string = parcBufferComposer_FinalizeBuffer(result);
+ * printf("JSON Array: %s\n", parcBuffer_ToString(string));
+ * parcBuffer_Release(&string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcJSONArray_BuildString(const PARCJSONArray *array, PARCBufferComposer *composer, bool compact);
+
+/**
+ * Produce a null-terminated string representation of the specified instance.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] array A pointer to the 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
+ * {
+ * PARCJSONArray *array = parcJSONArray_Create();
+ *
+ * PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415);
+ * parcJSONArray_AddValue(array, value);
+ * parcJSONValue_Release(&value);
+ *
+ * const char *string = parcJSONValue_ToString(array);
+ *
+ * parcMemory_Deallocate((void **) &string);
+ *
+ * parcJSONArray_Release(&array);
+ * }
+ * @endcode
+ *
+ * @see parcJSONArray_Display
+ */
+char *parcJSONArray_ToString(const PARCJSONArray *array);
+
+/**
+ * Produce a null-terminated compact string representation of the specified instance.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] array A pointer to the 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
+ * {
+ * PARCJSONArray *array = parcJSONArray_Create();
+ *
+ * PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415);
+ * parcJSONArray_AddValue(array, value);
+ * parcJSONValue_Release(&value);
+ *
+ * const char *string = parcJSONValue_ToCompactString(array);
+ *
+ * parcMemory_Deallocate((void **) &string);
+ *
+ * parcJSONArray_Release(&array);
+ * }
+ * @endcode
+ *
+ * @see parcJSONArray_Display
+ */
+char *parcJSONArray_ToCompactString(const PARCJSONArray *array);
+
+/**
+ * Pretty print the given `PARCJSONArray` instance.
+ *
+ * @param [in] array The `PARCJSONArray` instance to be printed.
+ * @param [in] indentation The amount of indentation to prefix each line of output
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *array = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+ * parcJSONArray_Display(array, 0);
+ * }
+ * @endcode
+ */
+void parcJSONArray_Display(const PARCJSONArray *array, int indentation);
+#endif // libparc_parc_JSONArray_h
diff --git a/libparc/parc/algol/parc_JSONPair.c b/libparc/parc/algol/parc_JSONPair.c
new file mode 100755
index 00000000..a5df700f
--- /dev/null
+++ b/libparc/parc/algol/parc_JSONPair.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.
+ */
+
+/**
+ * This does not properly implement the equals contract because the JSON object is stored in a PARCArrayList,
+ * which cannot compare elements other than by equal memory address.
+ *
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_JSONPair.h>
+#include <parc/algol/parc_JSONValue.h>
+#include <parc/algol/parc_JSONParser.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+struct parcJSONPair {
+ PARCBuffer *name;
+ PARCJSONValue *value;
+};
+
+static void
+_destroyJSONPair(PARCJSONPair **pairPtr)
+{
+ if (pairPtr != NULL) {
+ PARCJSONPair *pair = *pairPtr;
+ assertNotNull(pair, "Parameter must be a non-null pointer to a valid PARCJSONPair.");
+ parcBuffer_Release(&pair->name);
+ parcJSONValue_Release(&pair->value);
+ }
+}
+
+parcObject_ExtendPARCObject(PARCJSONPair, _destroyJSONPair, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static PARCJSONPair *
+_createJSONPair(void)
+{
+ return parcObject_CreateInstance(PARCJSONPair);
+}
+
+PARCJSONPair *
+parcJSONPair_Create(const PARCBuffer *name, PARCJSONValue *value)
+{
+ PARCJSONPair *result = _createJSONPair();
+ if (result != NULL) {
+ result->name = parcBuffer_Acquire(name);
+ result->value = parcJSONValue_Acquire(value);
+ }
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcJSONPair, PARCJSONPair);
+
+parcObject_ImplementRelease(parcJSONPair, PARCJSONPair);
+
+void
+parcJSONPair_Display(const PARCJSONPair *pair, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCJSONPair@%p {", pair);
+ parcBuffer_Display(pair->name, indentation + 1);
+ parcJSONValue_Display(pair->value, indentation + 1);
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+PARCBuffer *
+parcJSONPair_GetName(const PARCJSONPair *pair)
+{
+ return pair->name;
+}
+
+PARCJSONValue *
+parcJSONPair_GetValue(const PARCJSONPair *pair)
+{
+ return pair->value;
+}
+
+PARCJSONPair *
+parcJSONPair_CreateFromJSONValue(const char *name, PARCJSONValue *value)
+{
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(name);
+ PARCJSONPair *result = parcJSONPair_Create(nameBuffer, value);
+ parcBuffer_Release(&nameBuffer);
+
+ return result;
+}
+
+PARCJSONPair *
+parcJSONPair_CreateFromString(const char *name, const char *value)
+{
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(name);
+
+ PARCBuffer *valueBuffer = parcBuffer_AllocateCString(value);
+
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromString(valueBuffer);
+ parcBuffer_Release(&valueBuffer);
+
+ PARCJSONPair *result = parcJSONPair_Create(nameBuffer, jsonValue);
+ parcBuffer_Release(&nameBuffer);
+ parcJSONValue_Release(&jsonValue);
+
+ return result;
+}
+
+PARCJSONPair *
+parcJSONPair_CreateFromNULL(const char *name)
+{
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(name);
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromNULL();
+ PARCJSONPair *pair = parcJSONPair_Create(nameBuffer, jsonValue);
+ parcBuffer_Release(&nameBuffer);
+ parcJSONValue_Release(&jsonValue);
+
+ return pair;
+}
+
+PARCJSONPair *
+parcJSONPair_CreateFromBoolean(const char *name, bool value)
+{
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(name);
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromBoolean(value);
+ PARCJSONPair *pair = parcJSONPair_Create(nameBuffer, jsonValue);
+ parcBuffer_Release(&nameBuffer);
+ parcJSONValue_Release(&jsonValue);
+
+ return pair;
+}
+
+PARCJSONPair *
+parcJSONPair_CreateFromInteger(const char *name, int64_t value)
+{
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(name);
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromInteger(value);
+ PARCJSONPair *pair = parcJSONPair_Create(nameBuffer, jsonValue);
+ parcBuffer_Release(&nameBuffer);
+ parcJSONValue_Release(&jsonValue);
+
+ return pair;
+}
+
+PARCJSONPair *
+parcJSONPair_CreateFromDouble(const char *name, double value)
+{
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(name);
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromFloat(value);
+ PARCJSONPair *pair = parcJSONPair_Create(nameBuffer, jsonValue);
+ parcBuffer_Release(&nameBuffer);
+ parcJSONValue_Release(&jsonValue);
+
+ return pair;
+}
+
+PARCJSONPair *
+parcJSONPair_CreateFromJSONArray(const char *name, PARCJSONArray *value)
+{
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(name);
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromJSONArray(value);
+ PARCJSONPair *pair = parcJSONPair_Create(nameBuffer, jsonValue);
+ parcBuffer_Release(&nameBuffer);
+ parcJSONValue_Release(&jsonValue);
+
+ return pair;
+}
+
+PARCJSONPair *
+parcJSONPair_CreateFromJSON(const char *name, PARCJSON *value)
+{
+ PARCBuffer *nameBuffer = parcBuffer_AllocateCString(name);
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromJSON(value);
+ PARCJSONPair *pair = parcJSONPair_Create(nameBuffer, jsonValue);
+ parcBuffer_Release(&nameBuffer);
+ parcJSONValue_Release(&jsonValue);
+
+ return pair;
+}
+
+bool
+parcJSONPair_Equals(const PARCJSONPair *objA, const PARCJSONPair *objB)
+{
+ if (objA == NULL && objB == NULL) {
+ return true;
+ } else if (objA != NULL && objB != NULL) {
+ if (parcBuffer_Equals(objA->name, objB->name)) {
+ if (parcJSONValue_Equals(objA->value, objB->value)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+PARCBufferComposer *
+parcJSONPair_BuildString(const PARCJSONPair *pair, PARCBufferComposer *composer, bool compact)
+{
+ parcBufferComposer_PutUint8(composer, '"');
+
+ parcBufferComposer_PutBuffer(composer, pair->name);
+ parcBuffer_Rewind(pair->name);
+ if (compact) {
+ parcBufferComposer_PutString(composer, "\":");
+ } else {
+ parcBufferComposer_PutString(composer, "\" : ");
+ }
+ parcJSONValue_BuildString(pair->value, composer, compact);
+
+ return composer;
+}
+
+char *
+parcJSONPair_ToString(const PARCJSONPair *pair)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ parcJSONPair_BuildString(pair, composer, false);
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+PARCJSONPair *
+parcJSONPair_Parser(PARCJSONParser *parser)
+{
+ PARCJSONPair *result = NULL;
+
+ // This makes an unnecessary copy. I think this could just be a buffer slice.
+ PARCBuffer *name = parcJSONParser_ParseString(parser);
+ char c = parcJSONParser_NextChar(parser);
+ if (c == ':') {
+ PARCJSONValue *value = parcJSONValue_Parser(parser);
+ if (value != NULL) {
+ result = parcJSONPair_Create(name, value);
+ parcJSONValue_Release(&value);
+ }
+ }
+ parcBuffer_Release(&name);
+
+ return result;
+}
diff --git a/libparc/parc/algol/parc_JSONPair.h b/libparc/parc/algol/parc_JSONPair.h
new file mode 100755
index 00000000..dff8485b
--- /dev/null
+++ b/libparc/parc/algol/parc_JSONPair.h
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_JSON.h
+ * @ingroup inputoutput
+ * @brief JSON A JSON pair consists of a name and a value separated by a colon.
+ *
+ */
+#ifndef libparc_parc_JSONPair_h
+#define libparc_parc_JSONPair_h
+
+#include <stdbool.h>
+
+struct parcJSONPair;
+typedef struct parcJSONPair PARCJSONPair;
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_List.h>
+
+#include <parc/algol/parc_JSONArray.h>
+#include <parc/algol/parc_JSONValue.h>
+#include <parc/algol/parc_JSONParser.h>
+
+/**
+ * Create a new JSON Pair
+ *
+ * @param [in] name A pointer to a {@link PARCBuffer} instance containing the name for the JSON Pair.
+ * @param [in] value A pointer to a {@link PARCJSONValue} instance containing the value for the JSON Pair.
+ * @return A pointer to a new `PARCJSONPair`, or NULL if an error occured.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *name = parcBuffer_AllocateCString("myname");
+ * PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415);
+ * PARCJSONPair *pair = parcJSONPair_Create(name, value);
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see {@link parcJSONPair_CreateFromString}
+ * @see {@link parcJSONPair_CreateFromNULL}
+ * @see {@link parcJSONPair_CreateFromBoolean}
+ * @see {@link parcJSONPair_CreateFromInteger}
+ * @see {@link parcJSONPair_CreateFromDouble}
+ * @see {@link parcJSONPair_CreateFromJSONArray}
+ * @see {@link parcJSONPair_CreateFromJSON}
+ */
+PARCJSONPair *parcJSONPair_Create(const PARCBuffer *name, PARCJSONValue *value);
+
+/**
+ * Create a `PARCJSONPair` consisting of the given name and value represented as null-terminated C strings.
+ *
+ * @param [in] name A pointer to a null-terminated C string for the name of the `PARCJSONPair`.
+ * @param [in] value A pointer to a null-terminated C string for the value of the `PARCJSONPair`.
+ *
+ * @return A pointer to a `PARCJSONPair` instance, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromString("name", "value");
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONPair *parcJSONPair_CreateFromString(const char *name, const char *value);
+
+/**
+ * Create a `PARCJSONPair` consisting of the given name and `PARCJSONValue`.
+ *
+ * @param [in] name A pointer to a null-terminated C string for the name of the `PARCJSONPair`.
+ * @param [in] value A pointer to a `PARCJSONValue` for the value of the `PARCJSONPair`.
+ *
+ * @return A pointer to a `PARCJSONPair` instance, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromJSONValue("name", "value");
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONPair *parcJSONPair_CreateFromJSONValue(const char *name, PARCJSONValue *value);
+
+/**
+ * Create a `PARCJSONPair` consisting of the given name and the null value.
+ *
+ * @param [in] name A pointer to a null-terminated C string for the name of the `PARCJSONPair`.
+ *
+ * @return A pointer to a `PARCJSONPair` instance, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromNULL("name");
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONPair *parcJSONPair_CreateFromNULL(const char *name);
+
+/**
+ * Create a `PARCJSONPair` consisting of the given name and a JSON boolean of true or false as the value.
+ *
+ * @param [in] name A pointer to a null-terminated C string for the name of the `PARCJSONPair`.
+ * @param [in] value Either `true` or `false`.
+ *
+ * @return A pointer to a `PARCJSONPair` instance, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromBoolean("name", true);
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONPair *parcJSONPair_CreateFromBoolean(const char *name, bool value);
+
+/**
+ * Create a `PARCJSONPair` consisting of the given name and a JSON Integer.
+ *
+ * @param [in] name A pointer to a null-terminated C string for the name of the `PARCJSONPair`.
+ * @param [in] value An integer value.
+ *
+ * @return A pointer to a `PARCJSONPair` instance, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromInteger("name", 314159);
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONPair *parcJSONPair_CreateFromInteger(const char *name, int64_t value);
+
+/**
+ * Create a `PARCJSONPair` consisting of the given name and a JSON floating point value.
+ *
+ * @param [in] name A pointer to a null-terminated C string for the name of the `PARCJSONPair`.
+ * @param [in] value A double value.
+ *
+ * @return A pointer to a `PARCJSONPair` instance, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromDouble("name", 3.14159);
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONPair *parcJSONPair_CreateFromDouble(const char *name, double value);
+
+/**
+ * Create a `PARCJSONPair` consisting of the given name and a JSON Array.
+ *
+ * @param [in] name A pointer to a null-terminated C string for the name of the `PARCJSONPair`.
+ * @param [in] value A pointer to a {@link PARCJSONArray} instance for the value.
+ *
+ * @return A pointer to a `PARCJSONPair` instance, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *array = parcJSONArray_Create();
+ * PARCJSONPair *pair = parcJSONPair_CreateFromJSONArray("name", array);
+ * parcJSONArray_Release(&array);
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONPair *parcJSONPair_CreateFromJSONArray(const char *name, PARCJSONArray *value);
+
+/**
+ * Create a `PARCJSONPair` consisting of the given name and a JSON Object.
+ *
+ * @param [in] name A pointer to a null-terminated C string for the name of the `PARCJSONPair`.
+ * @param [in] value A pointer to a {@link PARCJSON} instance.
+ *
+ * @return A pointer to a `PARCJSONPair` instance, or NULL if an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json parcJSON_Create();
+ * PARCJSONPair *pair = parcJSONPair_CreateFromJSON("name", json);
+ * parcJSON_Release(&json);
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONPair *parcJSONPair_CreateFromJSON(const char *name, PARCJSON *value);
+
+/**
+ * Increase the number of references to a `PARCJSONPair` instance.
+ *
+ * A new instance is not created,
+ * only that the given instance's reference count is incremented.
+ * Discard the acquired reference by invoking {@link parcJSONPair_Release}.
+ *
+ * @param [in] pair A pointer to a `PARCJSONPair` instance.
+ * @return A pointer to the original instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromDouble("name", 3.14159);
+ *
+ * PARJSON *reference = parcJSONPair_Acquire(pair);
+ *
+ * parcJSONPair_Release(&pair);
+ * parcJSONPair_Release(&reference);
+ * }
+ * @endcode
+ */
+PARCJSONPair *parcJSONPair_Acquire(const PARCJSONPair *pair);
+
+/**
+ * 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.
+ *
+ * The contents of the deallocated memory used for the PARC object are undefined.
+ * Do not reference the object after the last release.
+ *
+ * @param [in,out] pairPtr A pointer to a pointer to the `PARCJSONPair` instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromDouble("name", 3.14159);
+ *
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ */
+void parcJSONPair_Release(PARCJSONPair **pairPtr);
+
+/**
+ * Get the {@link PARCBuffer} containing the name of the given `PARCJSONPair`.
+ *
+ * A new reference to the `PARCBuffer` is not created.
+ * The caller must create a new reference, if it retains a reference to the buffer.
+ *
+ * @param [in] pair A pointer to a `PARCJSONPair` instance.
+ *
+ * @return A pointer to a `PARCBuffer` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromDouble("name", 3.14159);
+ *
+ * const char *name = parcJSONPair_GetName(pair);
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCBuffer *parcJSONPair_GetName(const PARCJSONPair *pair);
+
+/**
+ * Print a human readable representation of the given `PARCJSONPair`.
+ *
+ * @param [in] pair A pointer to the instance to display.
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromDouble("name", 3.14159);
+ * parcJSONPair_Display(pair, 0);
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ */
+void parcJSONPair_Display(const PARCJSONPair *pair, int indentation);
+
+/**
+ * Get the {@link PARCJSONValue} containing the value of the given `PARCJSONPair`.
+ *
+ * A new reference to the `PARCJSONValue` is not created.
+ * The caller must create a new reference, if it retains a reference to the value instance.
+ *
+ * @param [in] pair A pointer to a `PARCJSONPair` instance.
+ *
+ * @return A pointer to a `PARCJSONValue` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *pair = parcJSONPair_CreateFromDouble("name", 3.14159);
+ * PARCJSONValue *value = parcJSONPair_GetValue(pair);
+ * parcJSONPair_Release(&pair);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_Create
+ */
+PARCJSONValue *parcJSONPair_GetValue(const PARCJSONPair *pair);
+
+/**
+ * Determine if two `PARCJSONPair` instances are equal.
+ *
+ * Two `PARCJSONPair` instances are equal if, and only if, their names and values are equal.
+ *
+ * The following equivalence relations on non-null `PARCJSONPair` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcJSONPair_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcJSONPair_Equals(x, y)` must return true if and only if
+ * `parcJSONPair_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcJSONPair_Equals(x, y)` returns true and
+ * `parcJSONPair_Equals(y, z)` returns true,
+ * then `parcJSONPair_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcJSONPair_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcJSONPair_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] x A pointer to a `PARCJSONPair` instance.
+ * @param [in] y A pointer to a `PARCJSONPair` instance.
+ * @return true if the two `PARCJSONPair` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONPair *a = parcJSONPair_Equals();
+ * PARCJSONPair *b = parcJSONPair_Equals();
+ *
+ * if (parcJSONPair_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool parcJSONPair_Equals(const PARCJSONPair *x, const PARCJSONPair *y);
+
+/**
+ * Produce a null-terminated string representation of the specified instance of `PARCJSONPair`.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] pair A pointer to the `PARCJSONPair` 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
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromInteger(123456);
+ * PARCJSONPair *instance = parcJSONPair_Create(parcBuffer_Wrap("Hello", 5, 0, 5), value);
+ * parcJSONValue_Release(&value);
+ *
+ * char *string = parcJSONPair_ToString(instance);
+ *
+ * if (string != NULL) {
+ * printf("%s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * parcJSONPair_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see parcJSONPair_BuildString
+ * @see parcJSONPair_Display
+ */
+char *parcJSONPair_ToString(const PARCJSONPair *pair);
+
+/**
+ * Append a representation of the specified instance to the given
+ * {@link PARCBufferComposer}.
+ *
+ * @param [in] pair A pointer to the `PARCJSONPair` instance.
+ * @param [in,out] composer A pointer to the `PARCBufferComposer` instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The given `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * parcJSONPair_BuildString(instance, result);
+ *
+ * PARCBuffer *string = parcBufferComposer_FinalizeBuffer(result);
+ * printf("Hello: %s\n", parcBuffer_ToString(string));
+ * parcBuffer_Release(&string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcJSONPair_BuildString(const PARCJSONPair *pair, PARCBufferComposer *composer, bool compact);
+
+/**
+ * Parse a complete JSON pair
+ *
+ * A pair consists of a name and a value separated by a colon.
+ *
+ * @param [in] parser A pointer to a {@link PARCJSONParser} instance.
+ *
+ * @return non-NULL A pointer to a valid `PARCJSONPair`
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_AllocateCString("\"name\" : \"value\"");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONPair *pair = parcJSONPair_Parser(parser);
+ *
+ * parcJSONPair_Release(&pair);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCJSONPair *parcJSONPair_Parser(PARCJSONParser *parser);
+#endif // libparc_parc_JSONPair_h
diff --git a/libparc/parc/algol/parc_JSONParser.c b/libparc/parc/algol/parc_JSONParser.c
new file mode 100755
index 00000000..a0022597
--- /dev/null
+++ b/libparc/parc/algol/parc_JSONParser.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 <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <ctype.h>
+#include <string.h>
+
+#include <parc/algol/parc_JSONParser.h>
+
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Object.h>
+
+struct parc_buffer_parser {
+ char *ignore;
+ PARCBuffer *buffer;
+};
+
+static PARCBuffer *
+_getBuffer(const PARCJSONParser *parser)
+{
+ return parser->buffer;
+}
+
+static void
+_destroyPARCBufferParser(PARCJSONParser **instancePtr)
+{
+ PARCJSONParser *parser = *instancePtr;
+ parcBuffer_Release(&parser->buffer);
+}
+
+parcObject_ExtendPARCObject(PARCJSONParser, _destroyPARCBufferParser, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCJSONParser *
+parcJSONParser_Create(PARCBuffer *buffer)
+{
+ PARCJSONParser *result = parcObject_CreateInstance(PARCJSONParser);
+ result->ignore = " \t\n";
+ result->buffer = parcBuffer_Acquire(buffer);
+ return result;
+}
+
+void
+parcJSONParser_AssertValid(const PARCJSONParser *parser)
+{
+ assertNotNull(parser, "PARCJSONParser cannot be NULL");
+ parcBuffer_OptionalAssertValid(parser->buffer);
+}
+
+parcObject_ImplementAcquire(parcJSONParser, PARCJSONParser);
+
+parcObject_ImplementRelease(parcJSONParser, PARCJSONParser);
+
+void
+parcJSONParser_SkipIgnored(PARCJSONParser *parser)
+{
+ parcJSONParser_OptionalAssertValid(parser);
+
+ parcBuffer_SkipOver(parser->buffer, strlen(parser->ignore), (uint8_t *) parser->ignore);
+}
+
+char
+parcJSONParser_NextChar(PARCJSONParser *parser)
+{
+ parcJSONParser_SkipIgnored(parser);
+ return (char) parcBuffer_GetUint8(parser->buffer);
+}
+
+bool
+parcJSONParser_Next(PARCJSONParser *parser, char *value)
+{
+ bool result = false;
+ parcJSONParser_SkipIgnored(parser);
+ if (parcJSONParser_Remaining(parser) > 0) {
+ *value = (char) parcBuffer_GetUint8(parser->buffer);
+ result = true;
+ }
+ return result;
+}
+
+char
+parcJSONParser_PeekNextChar(PARCJSONParser *parser)
+{
+ parcJSONParser_SkipIgnored(parser);
+ return (char) parcBuffer_PeekByte(parser->buffer);
+}
+
+void
+parcJSONParser_Advance(PARCJSONParser *parser, long bytes)
+{
+ parcJSONParser_OptionalAssertValid(parser);
+
+ parcBuffer_SetPosition(parser->buffer, parcBuffer_Position(parser->buffer) + bytes);
+}
+
+size_t
+parcJSONParser_Remaining(const PARCJSONParser *parser)
+{
+ parcJSONParser_OptionalAssertValid(parser);
+
+ return parcBuffer_Remaining(parser->buffer);
+}
+
+bool
+parcJSONParser_RequireString(PARCJSONParser *parser, const char *string)
+{
+ PARCBuffer *buffer = _getBuffer(parser);
+
+ for (const char *requiredCharacter = string; *requiredCharacter != 0; requiredCharacter++) {
+ uint8_t actualCharacter = parcBuffer_GetUint8(buffer);
+ if (actualCharacter != *requiredCharacter) {
+ return false;
+ }
+ }
+ return true;
+}
+
+PARCBuffer *
+parcJSONParser_ParseString(PARCJSONParser *parser)
+{
+ PARCBuffer *result = NULL;
+
+ PARCBuffer *buffer = _getBuffer(parser);
+ if (parcBuffer_GetUint8(buffer) == '"') { // skip the initial '"' character starting the string.
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ while (parcBuffer_Remaining(buffer)) {
+ uint8_t c = parcBuffer_GetUint8(buffer);
+ if (c == '"') {
+ // This is the only successful way to exit this while loop.
+ result = parcBufferComposer_ProduceBuffer(composer);
+ break;
+ } else if (c == '\\') {
+ c = parcBuffer_GetUint8(buffer);
+ if (c == '"') {
+ // this special character passes directly into the composed string.
+ } else if (c == '\\') {
+ // this special character passes directly into the composed string.
+ } else if (c == '/') {
+ // this special character passes directly into the composed string.
+ } else if (c == 'b') {
+ c = '\b';
+ } else if (c == 'f') {
+ c = '\f';
+ } else if (c == 'n') {
+ c = '\n';
+ } else if (c == 'r') {
+ c = '\r';
+ } else if (c == 't') {
+ c = '\t';
+ } else if (c == 'u') {
+ // Not supporting unicode at this point.
+ trapNotImplemented("Unicode is not supported.");
+ }
+ } else if (iscntrl(c)) {
+ // !! Syntax Error.
+ break;
+ }
+ parcBufferComposer_PutChar(composer, c);
+ }
+
+ parcBufferComposer_Release(&composer);
+ }
+ return result;
+}
diff --git a/libparc/parc/algol/parc_JSONParser.h b/libparc/parc/algol/parc_JSONParser.h
new file mode 100755
index 00000000..18ee9d1a
--- /dev/null
+++ b/libparc/parc/algol/parc_JSONParser.h
@@ -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.
+ */
+
+/**
+ * @file parc_JSONParser.h
+ * @brief A JSON parser
+ * @ingroup inputoutput
+ *
+ */
+#ifndef PARC_Library_parc_JSONParser_h
+#define PARC_Library_parc_JSONParser_h
+
+struct parc_buffer_parser;
+typedef struct parc_buffer_parser PARCJSONParser;
+
+#include <parc/algol/parc_Buffer.h>
+
+/**
+ * @def parcJSONValue_OptionalAssertValid
+ * Optional validation of the given instance.
+ *
+ * Define `PARCLibrary_DISABLE_VALIDATION` to nullify validation.
+ */
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcJSONParser_OptionalAssertValid(_instance_)
+#else
+# define parcJSONParser_OptionalAssertValid(_instance_) parcJSONParser_AssertValid(_instance_)
+#endif
+
+
+/**
+ * Create a new `PARCJSONParser`.
+ *
+ * @param [in] buffer A pointer to a {@link PARCBuffer} containing the data to parse.
+ *
+ * @return non-NULL A pointer to a valid `PARCJSONParser`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : 123 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ *
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCJSONParser *parcJSONParser_Create(PARCBuffer *buffer);
+
+/**
+ * Assert that an instance of `PARCJSONParser` 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] parser A pointer to a `PARCJSONParser` instance.
+ */
+void parcJSONParser_AssertValid(const PARCJSONParser *parser);
+
+/**
+ * Increase the number of references to a `PARCJSONParser`.
+ *
+ * Note that new `PARCJSONParser` is not created,
+ * only that the given `PARCJSONParser` reference count is incremented.
+ * Discard the reference by invoking {@link parcJSONParser_Release}.
+ *
+ * @param parser A pointer to the original instance.
+ * @return The value of the input parameter @p parser.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : 123 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONParser *x2 = parcJSONParser_Acquire(parser);
+ *
+ * parcJSONParser_Release(&parser);
+ * parcJSONParser_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see parcJSONParser_Release
+ */
+PARCJSONParser *parcJSONParser_Acquire(const PARCJSONParser *parser);
+
+/**
+ * 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.
+ *
+ * The contents of the dealloced memory used for the PARC object are undefined.
+ * Do not reference the object after the last release.
+ *
+ * @param [in,out] parserPtr A pointer to a pointer to the instance of `PARCJSONParser` to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : 123 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ *
+ * parcJSONParser_Release(&parser);
+ * }
+ * @endcode
+ */
+void parcJSONParser_Release(PARCJSONParser **parserPtr);
+
+/**
+ * Advance the parser, skipping any ignored characters.
+ *
+ * Ignored characters are space, tab and new-line.
+ *
+ * @param [in] parser A pointer to a `PARCJSONParser` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : 123 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * parcJSONParser_SkipIgnored(parser);
+ *
+ * parcJSONParser_Release(&parser);
+ * }
+ * @endcode
+ */
+void parcJSONParser_SkipIgnored(PARCJSONParser *parser);
+
+/**
+ * Get the next character from the parser.
+ *
+ * @param [in] parser A pointer to a `PARCJSONParser` instance.
+ *
+ * @return The next character
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : 123 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * char c = parcJSONParser_NextChar(parser);
+ *
+ * parcJSONParser_Release(&parser);
+ * }
+ * @endcode
+ */
+char parcJSONParser_NextChar(PARCJSONParser *parser);
+
+/**
+ * Get the next character from the parser, returning true or false if successful.
+ *
+ * @param [in] parser A pointer to a `PARCJSONParser` instance.
+ * @param [out] value A pointer to a `char` to contain the value if successful.
+ *
+ * @return true If successful
+ * @return false If unsuccessful
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : 123 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * bool success = parcJSONParser_Next(parser, &c);
+ *
+ * parcJSONParser_Release(&parser);
+ * }
+ * @endcode
+ */
+bool parcJSONParser_Next(PARCJSONParser *parser, char *value);
+
+/**
+ * Get the next character that the parser will process, but do not process it nor advance the parser.
+ *
+ * @param [in] parser A pointer to a `PARCJSONParser` instance.
+ *
+ * @return The next character that the parser will process.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : 123 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * char c = parcJSONParser_PeekNextChar(parser);
+ *
+ * parcJSONParser_Release(&parser);
+ * }
+ * @endcode
+ */
+char parcJSONParser_PeekNextChar(PARCJSONParser *parser);
+
+/**
+ * Advance the position of the parser forward or backward by the given number of bytes.
+ *
+ * To advance forward, bytes is a positive value.
+ * To advance backwards, bytes is a negative value.
+ *
+ * @param [in] parser A pointer to a valid `PARCJSONParser`.
+ * @param [in] bytes The number of bytes to move forward or backward.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("abcdef");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * parcJSONParser_Advance(parser, 2);
+ *
+ * parcJSONParser_Release(&parser);
+ * }
+ * @endcode
+ */
+void parcJSONParser_Advance(PARCJSONParser *parser, long bytes);
+
+/**
+ * Get the number of characters remaining to be parsed.
+ *
+ * @param [in] parser A pointer to a valid `PARCJSONParser` instance
+ *
+ * @return The number of characters remaining to be parsed.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("true);
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * size_t remaining = parcJSONParser_Remaining(parser);
+ *
+ * parcJSONParser_Release(&parser);
+ * }
+ * @endcode
+ */
+size_t parcJSONParser_Remaining(const PARCJSONParser *parser);
+
+/**
+ * Require the fixed string to appear in the current position of the parser.
+ *
+ * @param [in] parser A pointer to a `PARCJSONParser` instance.
+ * @param [in] string A pointer to a null-terminated C-string that must appear at the current position of the parser.
+ *
+ * @return true If the string appears.
+ * @return false If the string does not appear
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("true");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * bool result = parcJSONParser_RequireString(parser, "true");
+ *
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+bool parcJSONParser_RequireString(PARCJSONParser *parser, const char *string);
+
+/**
+ * Parse a JSON string returning a {@link PARCBuffer} containing the parsed string.
+ *
+ * A JSON string begins and ends with a non-escaped double-quote character.
+ *
+ * @param [in] parser A pointer to a `PARCJSONParser` instance.
+ *
+ * @return non-NULL A pointer to a valid `PARCBuffer`.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString("\"name\" : 123");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCBuffer *theName = parcJSONParser_ParseString(parser);
+ *
+ * parcJSONParser_Release(&parser);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcJSONParser_ParseString(PARCJSONParser *parser);
+
+#endif
diff --git a/libparc/parc/algol/parc_JSONValue.c b/libparc/parc/algol/parc_JSONValue.c
new file mode 100755
index 00000000..3a3ba9cd
--- /dev/null
+++ b/libparc/parc/algol/parc_JSONValue.c
@@ -0,0 +1,1018 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <ctype.h>
+#include <math.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <parc/algol/parc_JSONValue.h>
+#include <parc/algol/parc_JSON.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Object.h>
+
+typedef enum {
+ PARCJSONValueType_Boolean,
+ PARCJSONValueType_String,
+ PARCJSONValueType_Number,
+ PARCJSONValueType_Array,
+ PARCJSONValueType_JSON,
+ PARCJSONValueType_Null
+} _PARCJSONValueType;
+
+struct parc_json_value {
+ _PARCJSONValueType type;
+
+ union {
+ bool boolean;
+ PARCBuffer *string;
+ int64_t intValue;
+ PARCList *_array;
+ PARCJSONArray *array;
+ PARCJSON *object;
+ struct {
+ bool internalDoubleRepresentation;
+ long double internalDoubleValue;
+
+ int sign;
+ int64_t whole;
+ int64_t fraction;
+ int64_t fractionLog10;
+ int64_t exponent;
+ } number;
+ } value;
+};
+
+
+
+static void
+_parcJSONValueDestroy(PARCJSONValue **valuePtr)
+{
+ if (valuePtr != NULL) {
+ PARCJSONValue *value = *valuePtr;
+ if (value->type == PARCJSONValueType_Array) {
+ parcJSONArray_Release(&value->value.array);
+ } else if (value->type == PARCJSONValueType_JSON) {
+ parcJSON_Release(&value->value.object);
+ } else if (value->type == PARCJSONValueType_String) {
+ parcBuffer_Release(&value->value.string);
+ }
+ }
+}
+
+parcObject_ExtendPARCObject(PARCJSONValue, _parcJSONValueDestroy, NULL, NULL, parcJSONValue_Equals, NULL, NULL, NULL);
+
+static PARCJSONValue *
+_createValue(_PARCJSONValueType type)
+{
+ PARCJSONValue *result = parcObject_CreateAndClearInstance(PARCJSONValue);
+
+ if (result != NULL) {
+ result->type = type;
+ }
+ return result;
+}
+
+/**
+ * Return true if the parser is currently positioned at the valid beginning of a number.
+ * If true, then return the sign (-1, +1) in the integer pointed to by @p sign.
+ * If false, then return false ensuring that the parser is repositioned to where it started.
+ */
+static bool
+_parseSign(PARCJSONParser *parser, int *sign)
+{
+ if (parcJSONParser_Remaining(parser) > 0) {
+ uint8_t c = parcJSONParser_NextChar(parser);
+ if (c == '-') {
+ *sign = -1;
+ return true;
+ }
+ if (!isdigit(c)) {
+ return false;
+ }
+ parcJSONParser_Advance(parser, -1);
+ }
+ *sign = 1;
+ return true;
+}
+
+static PARCJSONValue *
+_parcJSONValue_FalseParser(PARCJSONParser *parser)
+{
+ PARCJSONValue *result = NULL;
+
+ if (parcJSONParser_RequireString(parser, "false")) {
+ result = parcJSONValue_CreateFromBoolean(false);
+ }
+ return result;
+}
+
+static PARCJSONValue *
+_parcJSONValue_NullParser(PARCJSONParser *parser)
+{
+ PARCJSONValue *result = NULL;
+
+ if (parcJSONParser_RequireString(parser, "null")) {
+ result = parcJSONValue_CreateFromNULL();
+ }
+ return result;
+}
+
+static PARCJSONValue *
+_parcJSONValue_TrueParser(PARCJSONParser *parser)
+{
+ PARCJSONValue *result = NULL;
+
+ if (parcJSONParser_RequireString(parser, "true")) {
+ result = parcJSONValue_CreateFromBoolean(true);
+ }
+ return result;
+}
+
+static PARCJSONValue *
+_parcJSONValue_StringParser(PARCJSONParser *parser)
+{
+ PARCJSONValue *result = NULL;
+ PARCBuffer *string = parcJSONParser_ParseString(parser);
+
+ if (string != NULL) {
+ result = parcJSONValue_CreateFromString(string);
+ parcBuffer_Release(&string);
+ }
+
+ return result;
+}
+
+static int
+_digittoint(char digit)
+{
+ return digit - '0';
+}
+
+/*
+ * Parse the whole number portion of a number.
+ *
+ * 0
+ * [1-9][0-9]*
+ */
+static bool
+_parseWholeNumber(PARCJSONParser *parser, int64_t *value)
+{
+ bool result = false;
+ int sign = 1;
+
+ char nextCharacter;
+
+ if (parcJSONParser_Next(parser, &nextCharacter)) {
+ if (nextCharacter == '0') {
+ *value = 0;
+ result = true;
+ } else if (isdigit(nextCharacter)) {
+ *value = _digittoint(nextCharacter);
+ while (parcJSONParser_Next(parser, &nextCharacter)) {
+ if (!isdigit(nextCharacter)) {
+ parcJSONParser_Advance(parser, -1);
+ break;
+ }
+ *value = *value * 10 + _digittoint(nextCharacter);
+ }
+ *value = *value * sign;
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+static bool
+_parseFractionNumber(PARCJSONParser *parser, int64_t *value, int *log10)
+{
+ bool result = false;
+
+ if (parcJSONParser_Remaining(parser) > 0) {
+ *value = 0;
+ *log10 = 0;
+ char nextCharacter;
+ while (parcJSONParser_Next(parser, &nextCharacter)) {
+ if (!isdigit(nextCharacter)) {
+ parcJSONParser_Advance(parser, -1);
+ break;
+ }
+ *value = *value * 10 + _digittoint(nextCharacter);
+ *log10 = *log10 + 1;
+ }
+
+ result = true;
+ }
+
+ return result;
+}
+
+/**
+ * Parse an optional fractional part of a number.
+ *
+ * If the parser is positioned at a '.' character, then parse a fraction comprised of numbers.
+ * Otherwise, if the parser is positioned at a 'e' ',' ']' or '}' then there is no fraction, but not an error.
+ * If the parser is positioned at any other character, then it is a syntax error.
+ *
+ * @param [in] parser A pointer to a PARCJSONParser instance.
+ * @param [out] value A pointer to an integer accumulating the fraction as a whole number.
+ * @param [out] log10 A pointer to an integer accumulating the base 10 logarithm of the fraction (as a positive integer).
+ *
+ * @return true If there was no syntax error.
+ * @return false If there was a syntax error.
+ */
+static bool
+_parseOptionalFraction(PARCJSONParser *parser, int64_t *value, int *log10)
+{
+ bool result = true;
+
+ // The parser is either looking at an '.' which signals the start of a fractional part,
+ // or a 'e' ',' ']' or '}' which signals a missing fractional part.
+ // Any other character would be the beginning of a syntax error.
+
+ char nextCharacter;
+
+ if (parcJSONParser_Next(parser, &nextCharacter)) {
+ if (nextCharacter == '.') {
+ if (_parseFractionNumber(parser, value, log10) == false) {
+ result = false;
+ }
+ } else if (nextCharacter == 'e' || nextCharacter == ',' || nextCharacter == ']' || nextCharacter == '}') {
+ parcJSONParser_Advance(parser, -1);
+ result = true;
+ } else {
+ parcJSONParser_Advance(parser, -1);
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Parse and compute the base 10 value of a a sequence of digits from 0 to 9, inclusive.
+ *
+ * @param [in] parser A pointer to a PARCJSONParser instance.
+ * @param [out] value A pointer to a value that will receive the base 10 value.
+ *
+ * @return true If there were parsable digits.
+ */
+static bool
+_parseDigits09(PARCJSONParser *parser, int64_t *value)
+{
+ bool result = false;
+
+ *value = 0;
+ char nextDigit;
+ while (parcJSONParser_Next(parser, &nextDigit)) {
+ *value = *value * 10 + _digittoint(nextDigit);
+ result = true;
+ }
+
+ return result;
+}
+
+static bool
+_parseExponentNumber(PARCJSONParser *parser, int64_t *value)
+{
+ bool result = false;
+ int sign = 1;
+
+ char nextCharacter;
+ if (parcJSONParser_Next(parser, &nextCharacter)) {
+ if (nextCharacter == '-') {
+ sign = -1;
+ if (_parseDigits09(parser, value)) {
+ result = true;
+ }
+ *value = *value * sign;
+ } else if (nextCharacter == '+') {
+ sign = 1;
+ if (_parseDigits09(parser, value)) {
+ result = true;
+ }
+ *value = *value * sign;
+ } else if (isdigit(nextCharacter)) {
+ parcJSONParser_Advance(parser, -1);
+ if (_parseDigits09(parser, value)) {
+ result = true;
+ }
+ *value = *value * sign;
+ } else {
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+static bool
+_parseOptionalExponent(PARCJSONParser *parser, int64_t *value)
+{
+ // The parser is either looking at a 'e' or 'E' ',' ']' or '}'
+ bool result = true;
+
+ char nextCharacter;
+ if (parcJSONParser_Next(parser, &nextCharacter)) {
+ if (nextCharacter == 'e' || nextCharacter == 'E') {
+ if (_parseExponentNumber(parser, value) == false) {
+ result = false;
+ }
+ } else if (nextCharacter == ',' || nextCharacter == ']' || nextCharacter == '}') {
+ parcJSONParser_Advance(parser, -1);
+ result = true;
+ } else {
+ parcJSONParser_Advance(parser, -1);
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+static __attribute__ ((noinline)) PARCJSONValue *
+_parcJSONValue_CreateNumber(int sign, int64_t whole, int64_t fraction, int64_t fractionLog10, int64_t exponent)
+{
+ PARCJSONValue *result = _createValue(PARCJSONValueType_Number);
+ if (result != NULL) {
+ result->value.number.sign = sign;
+ result->value.number.whole = whole;
+ result->value.number.fraction = fraction;
+ result->value.number.fractionLog10 = fractionLog10;
+ result->value.number.exponent = exponent;
+ }
+ return result;
+}
+
+static PARCJSONValue *
+_parcJSONValue_NumberParser(PARCJSONParser *parser)
+{
+ PARCJSONValue *result = NULL;
+ int sign = 1;
+ int64_t whole = 0;
+ int64_t fraction = 0;
+ int64_t exponent = 0;
+ int fractionLog10 = 0;
+
+ if (_parseSign(parser, &sign)) {
+ if (_parseWholeNumber(parser, &whole)) {
+ if (_parseOptionalFraction(parser, &fraction, &fractionLog10)) {
+ if (_parseOptionalExponent(parser, &exponent)) {
+ result = _parcJSONValue_CreateNumber(sign, whole, fraction, fractionLog10, exponent);
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static PARCJSONValue *
+_parcJSONValue_ArrayParser(PARCJSONParser *parser)
+{
+ PARCJSONValue *result = NULL;
+
+ if (parcJSONParser_NextChar(parser) == '[') {
+ PARCJSONArray *array = parcJSONArray_Create();
+
+ while (parcJSONParser_Remaining(parser)) {
+ char peek = parcJSONParser_PeekNextChar(parser);
+ if (peek == ',') {
+ parcJSONParser_NextChar(parser);
+ } else if (peek == ']') {
+ parcJSONParser_NextChar(parser); // absorb the ']' character
+ result = parcJSONValue_CreateFromJSONArray(array);
+ parcJSONArray_Release(&array);
+ break;
+ } else {
+ PARCJSONValue *value = NULL;
+
+ if (peek == 'n') {
+ value = _parcJSONValue_NullParser(parser);
+ } else if (peek == 't') {
+ value = _parcJSONValue_TrueParser(parser);
+ } else if (peek == 'f') {
+ value = _parcJSONValue_FalseParser(parser);
+ } else if (peek == '"') {
+ value = _parcJSONValue_StringParser(parser);
+ } else if (peek == '{') {
+ value = parcJSONValue_ObjectParser(parser);
+ } else if (peek == '[') {
+ value = _parcJSONValue_ArrayParser(parser);
+ } else {
+ value = _parcJSONValue_NumberParser(parser);
+ }
+
+ if (value != NULL) {
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+ } else {
+ parcJSONArray_Release(&array);
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static void
+_displayBoolean(const PARCJSONValue *value, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, ".value=%s", value->value.boolean == true ? "true" : "false");
+}
+
+static void
+_displayNumber(const PARCJSONValue *value, int indentation)
+{
+ if (value->value.number.internalDoubleRepresentation) {
+ parcDisplayIndented_PrintLine(indentation, ".value=%Lf", value->value.number.internalDoubleValue);
+ } else {
+ parcDisplayIndented_PrintLine(indentation,
+ ".value.number={ sign=%d whole=%lld fractionLog10=%d fraction=%lld exponent=%lld",
+ value->value.number.sign,
+ value->value.number.whole,
+ (int) value->value.number.fractionLog10,
+ value->value.number.fraction,
+ value->value.number.exponent);
+ }
+}
+
+void
+parcJSONValue_AssertValid(const PARCJSONValue *value)
+{
+ assertNotNull(value, "PARCJSONValue cannot be NULL.");
+}
+
+bool
+parcJSONValue_IsValid(const PARCJSONValue *value)
+{
+ bool result = true;
+
+ if (value == NULL) {
+ result = false;
+ }
+
+ return result;
+}
+
+bool
+parcJSONValue_IsNull(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ return (value->type == PARCJSONValueType_Null);
+}
+
+bool
+parcJSONValue_IsBoolean(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ return (value->type == PARCJSONValueType_Boolean);
+}
+
+bool
+parcJSONValue_IsNumber(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ return (value->type == PARCJSONValueType_Number);
+}
+
+bool
+parcJSONValue_IsJSON(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ return (value->type == PARCJSONValueType_JSON);
+}
+
+bool
+parcJSONValue_IsString(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ return (value->type == PARCJSONValueType_String);
+}
+
+bool
+parcJSONValue_IsArray(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ return (value->type == PARCJSONValueType_Array);
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromNULL(void)
+{
+ // Strictly speaking, this could just be a singleton, rather than allocated every time.
+
+ PARCJSONValue *result = _createValue(PARCJSONValueType_Null);
+
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromBoolean(bool value)
+{
+ PARCJSONValue *result = _createValue(PARCJSONValueType_Boolean);
+ if (result != NULL) {
+ result->value.boolean = value;
+ }
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromFloat(long double value)
+{
+ PARCJSONValue *result = _parcJSONValue_CreateNumber(0, 0, 0, 0, 0);
+ result->value.number.internalDoubleRepresentation = true;
+ result->value.number.internalDoubleValue = value;
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromInteger(int64_t value)
+{
+ PARCJSONValue *result = _parcJSONValue_CreateNumber(1, value, 0, 0, 0);
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromString(PARCBuffer *value)
+{
+ parcBuffer_OptionalAssertValid(value);
+
+ PARCJSONValue *result = _createValue(PARCJSONValueType_String);
+ if (result != NULL) {
+ result->value.string = parcBuffer_Acquire(value);
+ }
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromCString(const char *value)
+{
+ assertNotNull(value, "String cannot be NULL.");
+
+ PARCJSONValue *result = _createValue(PARCJSONValueType_String);
+ if (result != NULL) {
+ result->value.string = parcBuffer_AllocateCString(value);
+ }
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromJSONArray(PARCJSONArray *value)
+{
+ PARCJSONValue *result = _createValue(PARCJSONValueType_Array);
+ if (result != NULL) {
+ result->value.array = parcJSONArray_Acquire(value);
+ }
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromJSON(PARCJSON *value)
+{
+ PARCJSONValue *result = _createValue(PARCJSONValueType_JSON);
+ if (result != NULL) {
+ result->value.object = parcJSON_Acquire(value);
+ }
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromTimeval(const struct timeval *timeval)
+{
+ PARCJSON *jsonTimeval = parcJSON_Create();
+ parcJSON_AddInteger(jsonTimeval, "seconds", timeval->tv_sec);
+ parcJSON_AddInteger(jsonTimeval, "micros", timeval->tv_usec);
+
+ PARCJSONValue *result = _createValue(PARCJSONValueType_JSON);
+ if (result != NULL) {
+ result->value.object = jsonTimeval;
+ }
+
+ return result;
+}
+
+PARCJSONValue *
+parcJSONValue_CreateFromTimespec(const struct timespec *timespec)
+{
+ PARCJSON *jsonTimespec = parcJSON_Create();
+ parcJSON_AddInteger(jsonTimespec, "seconds", timespec->tv_sec);
+ parcJSON_AddInteger(jsonTimespec, "nanos", timespec->tv_nsec);
+
+ PARCJSONValue *result = _createValue(PARCJSONValueType_JSON);
+ if (result != NULL) {
+ result->value.object = jsonTimespec;
+ }
+
+ return result;
+}
+
+void
+parcJSONValue_Display(const PARCJSONValue *value, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCJSONValue@%p {", value);
+ if (value != NULL) {
+ parcDisplayIndented_PrintLine(indentation + 1, ".type=%d", value->type);
+
+ switch (value->type) {
+ case PARCJSONValueType_Boolean:
+ _displayBoolean(value, indentation + 1);
+ break;
+ case PARCJSONValueType_String:
+ parcBuffer_Display(value->value.string, indentation + 1);
+ break;
+ case PARCJSONValueType_Number:
+ _displayNumber(value, indentation + 1);
+ break;
+ case PARCJSONValueType_Array:
+ parcJSONArray_Display(value->value.array, indentation + 1);
+ break;
+ case PARCJSONValueType_JSON:
+ parcJSON_Display(value->value.object, indentation + 1);
+ break;
+ case PARCJSONValueType_Null:
+ parcDisplayIndented_PrintLine(indentation + 1, ".value=null");
+ break;
+ default:
+ trapIllegalValue(value->type, "Unknown PARCJSONValue type %d", value->type);
+ }
+ }
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+parcObject_ImplementAcquire(parcJSONValue, PARCJSONValue);
+
+parcObject_ImplementRelease(parcJSONValue, PARCJSONValue);
+
+static bool
+_equalsNumber(const PARCJSONValue *valueA, const PARCJSONValue *valueB)
+{
+ bool result = false;
+
+ if (valueA->value.number.internalDoubleRepresentation) {
+ if (valueB->value.number.internalDoubleRepresentation) {
+ if (valueA->value.number.internalDoubleValue == valueB->value.number.internalDoubleValue) {
+ result = true;
+ }
+ }
+ } else {
+ if (valueA->value.number.sign == valueB->value.number.sign) {
+ if (valueA->value.number.whole == valueB->value.number.whole) {
+ if (valueA->value.number.fraction == valueB->value.number.fraction) {
+ if (valueA->value.number.exponent == valueB->value.number.exponent) {
+ result = true;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+bool
+parcJSONValue_Equals(const PARCJSONValue *objA, const PARCJSONValue *objB)
+{
+ bool result = false;
+
+ if (objA == NULL || objB == NULL) {
+ result = (objA == objB);
+ } else {
+ if (objA->type == objB->type) {
+ switch (objA->type) {
+ case PARCJSONValueType_Boolean:
+ result = objA->value.boolean == objB->value.boolean;
+ break;
+ case PARCJSONValueType_String:
+ result = parcBuffer_Equals(objA->value.string, objB->value.string);
+ break;
+ case PARCJSONValueType_Number:
+ result = _equalsNumber(objA, objB);
+ break;
+ case PARCJSONValueType_Array:
+ result = parcJSONArray_Equals(objA->value.array, objB->value.array);
+ break;
+ case PARCJSONValueType_JSON:
+ result = parcJSON_Equals(objA->value.object, objB->value.object);
+ break;
+ case PARCJSONValueType_Null:
+ result = true;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCJSONArray *
+parcJSONValue_GetArray(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ trapUnexpectedStateIf(!parcJSONValue_IsArray(value), "Expected type to be array, actual type %d", value->type);
+
+ return value->value.array;
+}
+
+bool
+parcJSONValue_GetBoolean(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ trapUnexpectedStateIf(!parcJSONValue_IsBoolean(value), "Expected type to be boolean, actual type %d", value->type);
+
+ return value->value.boolean;
+}
+
+static long double
+_parcJSONValue_GetNumber(const PARCJSONValue *value)
+{
+ long double fraction = value->value.number.fraction / powl(10.0, value->value.number.fractionLog10);
+ long double number = (long double) value->value.number.sign * ((long double) value->value.number.whole + fraction);
+
+ long double result = number * powl(10.0, (long double) value->value.number.exponent);
+
+ return result;
+}
+
+long double
+parcJSONValue_GetFloat(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ long double result = 0;
+
+ if (value->value.number.internalDoubleRepresentation) {
+ result = value->value.number.internalDoubleValue;
+ } else {
+ result = _parcJSONValue_GetNumber(value);
+ }
+
+ return result;
+}
+
+int64_t
+parcJSONValue_GetInteger(const PARCJSONValue *value)
+{
+ int64_t result = llrint(_parcJSONValue_GetNumber(value));
+ return result;
+}
+
+PARCBuffer *
+parcJSONValue_GetString(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ trapUnexpectedStateIf(!parcJSONValue_IsString(value), "Expected type to be string, actual type %d", value->type);
+
+ return value->value.string;
+}
+
+PARCJSON *
+parcJSONValue_GetJSON(const PARCJSONValue *value)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ trapUnexpectedStateIf(!parcJSONValue_IsJSON(value), "Expected type to be string, actual type %d", value->type);
+
+ return value->value.object;
+}
+
+struct timeval *
+parcJSONValue_GetTimeval(const PARCJSONValue *jsonTimeval, struct timeval *timeval)
+{
+ assertNotNull(jsonTimeval, "Parameter jsonTimeval must be a non-null PARCJSON pointer.");
+
+ PARCJSON *json = parcJSONValue_GetJSON(jsonTimeval);
+ PARCJSONValue *value = parcJSON_GetValueByName(json, "seconds");
+ timeval->tv_sec = parcJSONValue_GetInteger(value);
+ value = parcJSON_GetValueByName(json, "micros");
+ timeval->tv_usec = (int) parcJSONValue_GetInteger(value);
+
+ return timeval;
+}
+
+struct timespec *
+parcJSONValue_GetTimespec(const PARCJSONValue *jsonTimespec, struct timespec *timespec)
+{
+ assertNotNull(jsonTimespec, "Parameter jsonTimeval must be a non-null PARCJSON pointer.");
+
+ PARCJSON *json = parcJSONValue_GetJSON(jsonTimespec);
+ PARCJSONValue *value = parcJSON_GetValueByName(json, "seconds");
+ timespec->tv_sec = parcJSONValue_GetInteger(value);
+ value = parcJSON_GetValueByName(json, "nanos");
+ timespec->tv_nsec = (int) parcJSONValue_GetInteger(value);
+
+ return timespec;
+}
+
+static PARCBufferComposer *
+_buildStringNumber(const PARCJSONValue *value, PARCBufferComposer *string)
+{
+ if (value->value.number.internalDoubleRepresentation) {
+ parcBufferComposer_Format(string, "%Lf", value->value.number.internalDoubleValue);
+ } else {
+ parcBufferComposer_Format(string, "%s%" PRId64,
+ value->value.number.sign == -1 ? "-" : "",
+ value->value.number.whole);
+ if (value->value.number.fraction > 0) {
+ parcBufferComposer_Format(string, ".%0*" PRId64,
+ (int) value->value.number.fractionLog10,
+ value->value.number.fraction);
+ }
+
+ if (value->value.number.exponent != 0) {
+ parcBufferComposer_Format(string, "e%" PRId64,
+ value->value.number.exponent);
+ }
+ }
+ return string;
+}
+
+static PARCBufferComposer *
+_buildStringString(const PARCJSONValue *value, PARCBufferComposer *composer, bool compact)
+{
+ parcBufferComposer_PutChar(composer, '"');
+
+ while (parcBuffer_Remaining(value->value.string)) {
+ uint8_t c = parcBuffer_GetUint8(value->value.string);
+ if (c == '"') {
+ parcBufferComposer_PutString(composer, "\\\"");
+ } else if (c == '\b') {
+ parcBufferComposer_PutString(composer, "\\b");
+ } else if (c == '\f') {
+ parcBufferComposer_PutString(composer, "\\f");
+ } else if (c == '\n') {
+ parcBufferComposer_PutString(composer, "\\n");
+ } else if (c == '\r') {
+ parcBufferComposer_PutString(composer, "\\r");
+ } else if (c == '\t') {
+ parcBufferComposer_PutString(composer, "\\t");
+ } else if ((c == '/') && !compact) {
+ parcBufferComposer_PutString(composer, "\\/");
+ } else if (c == '\\') {
+ parcBufferComposer_PutString(composer, "\\\\");
+ } else {
+ parcBufferComposer_PutChar(composer, c);
+ }
+ }
+
+ parcBuffer_Rewind(value->value.string);
+ parcBufferComposer_PutChar(composer, '"');
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcJSONValue_BuildString(const PARCJSONValue *value, PARCBufferComposer *composer, bool compact)
+{
+ parcJSONValue_OptionalAssertValid(value);
+
+ if (value->type == PARCJSONValueType_Boolean) {
+ parcBufferComposer_PutString(composer, value->value.boolean ? "true" : "false");
+ } else if (value->type == PARCJSONValueType_String) {
+ _buildStringString(value, composer, compact);
+ } else if (value->type == PARCJSONValueType_Number) {
+ _buildStringNumber(value, composer);
+ } else if (value->type == PARCJSONValueType_Array) {
+ parcJSONArray_BuildString(value->value.array, composer, compact);
+ } else if (value->type == PARCJSONValueType_JSON) {
+ parcJSON_BuildString(value->value.object, composer, compact);
+ } else if (value->type == PARCJSONValueType_Null) {
+ parcBufferComposer_PutString(composer, "null");
+ } else {
+ trapIllegalValue(value->type, "Unknown value type: %d", value->type);
+ }
+
+ return composer;
+}
+
+static char *
+_parcJSONValue_ToString(const PARCJSONValue *value, bool compact)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcJSONValue_BuildString(value, composer, compact);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+char *
+parcJSONValue_ToString(const PARCJSONValue *value)
+{
+ return _parcJSONValue_ToString(value, false);
+}
+
+char *
+parcJSONValue_ToCompactString(const PARCJSONValue *value)
+{
+ return _parcJSONValue_ToString(value, true);
+}
+
+PARCJSONValue *
+parcJSONValue_Parser(PARCJSONParser *parser)
+{
+ char nextCharacter = parcJSONParser_PeekNextChar(parser);
+ switch (nextCharacter) {
+ case ',':
+ break;
+
+ case ']':
+ return NULL;
+
+ case 'n':
+ return _parcJSONValue_NullParser(parser);
+
+ case 't':
+ return _parcJSONValue_TrueParser(parser);
+
+ case 'f':
+ return _parcJSONValue_FalseParser(parser);
+
+ case '"':
+ return _parcJSONValue_StringParser(parser);
+
+ case '[':
+ return _parcJSONValue_ArrayParser(parser);
+
+ case '{':
+ return parcJSONValue_ObjectParser(parser);
+
+ default:
+ return _parcJSONValue_NumberParser(parser);
+ }
+
+ return NULL;
+}
+
+PARCJSONValue *
+parcJSONValue_ObjectParser(PARCJSONParser *parser)
+{
+ PARCJSONValue *result = NULL;
+
+ // absorb the (required) '{' character.
+ if (parcJSONParser_NextChar(parser) == '{') {
+ PARCJSON *json = parcJSON_Create();
+
+ while (parcJSONParser_Remaining(parser)) {
+ char c = parcJSONParser_PeekNextChar(parser);
+ if (c == '}') {
+ // Absorb the '}' and terminate.
+ parcJSONParser_NextChar(parser);
+ result = parcJSONValue_CreateFromJSON(json);
+ break;
+ } else if (c == ',') {
+ // absorb the ',' character and continue
+ parcJSONParser_NextChar(parser);
+ } else if (c == '"') {
+ PARCJSONPair *pair = parcJSONPair_Parser(parser);
+ if (pair == NULL) {
+ break;
+ }
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+ } else {
+ break;
+ }
+ }
+ parcJSON_Release(&json);
+ }
+
+ return result;
+}
+
diff --git a/libparc/parc/algol/parc_JSONValue.h b/libparc/parc/algol/parc_JSONValue.h
new file mode 100755
index 00000000..300a1c0c
--- /dev/null
+++ b/libparc/parc/algol/parc_JSONValue.h
@@ -0,0 +1,938 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_JSON.h
+ * @ingroup inputoutput
+ * @brief A JSON value. One of a Boolean, String, Number, JSON Array, JSON Object, or Null.
+ *
+ */
+#ifndef libparc_parc_JSONValue_h
+#define libparc_parc_JSONValue_h
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct parc_json_value;
+typedef struct parc_json_value PARCJSONValue;
+
+#include <parc/algol/parc_Object.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_JSONParser.h>
+#include <parc/algol/parc_JSONPair.h>
+#include <parc/algol/parc_JSONArray.h>
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_List.h>
+
+/**
+ * @def parcJSONValue_OptionalAssertValid
+ * Optional validation of the given instance.
+ *
+ * Define `PARCLibrary_DISABLE_VALIDATION` to nullify validation.
+ */
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcJSONValue_OptionalAssertValid(_instance_)
+#else
+# define parcJSONValue_OptionalAssertValid(_instance_) parcJSONValue_AssertValid(_instance_)
+#endif
+
+/**
+ * Print a human readable representation of the given `PARCJSONValue`.
+ *
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ * @param [in] value A pointer to the instance of `PARCJSONValue` to display.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *instance = parcJSONValue_CreateFromNull();
+ *
+ * parcJSONValue_Display(instance, 0);
+ *
+ * parcJSONValue_Release(&instance);
+ * }
+ * @endcode
+ *
+ */
+void parcJSONValue_Display(const PARCJSONValue *value, int indentation);
+
+/**
+ * Determine if @p value is a JSON Null.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return True if @p value is a JSON Null.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ *
+ * if (parcJSONValue_IsNull(value)) {
+ * printf("Success!\n");
+ * }
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_CreateFromNULL
+ */
+bool parcJSONValue_IsNull(const PARCJSONValue *value);
+
+/**
+ * Determine if @p value is a JSON Boolean.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return True if @p value is a JSON Boolean.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromBoolean(true);
+ *
+ * if (parcJSONValue_IsBoolean(value)) {
+ * printf("Success!\n");
+ * }
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_CreateFromNULL
+ */
+bool parcJSONValue_IsBoolean(const PARCJSONValue *value);
+
+/**
+ * Determine if @p value is a JSON Number.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return True if @p value is a JSON Number.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromFloat(3.14);
+ *
+ * if (parcJSONValue_IsNumber(value)) {
+ * printf("Success!\n");
+ * }
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_GetInteger
+ * @see parcJSONValue_GetFloat
+ */
+bool parcJSONValue_IsNumber(const PARCJSONValue *value);
+
+/**
+ * Determine if the pointer to a `PARCJSONValue` is valid.
+ *
+ * @param [in] value A pointer to a `PARCJSONValue`.
+ *
+ * @return true The `PARCJSONValue` is valid.
+ * @return false The `PARCJSONValue` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_Create());
+ * PARCJSONValue *value = parcJSONValue_CreateFromJSON(json);
+ * parcJSON_Release(&json);
+ *
+ * if (parcJSONValue_IsValid(value)) {
+ * printf("Valid!\n");
+ * } else {
+ * printf("Invalid!\n");
+ * }
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ */
+bool parcJSONValue_IsValid(const PARCJSONValue *value);
+
+/**
+ * Assert that an instance of `PARCJSONValue` 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] value A pointer to a `PARCJSONValue` instance.
+ */
+void parcJSONValue_AssertValid(const PARCJSONValue *value);
+
+/**
+ * Determine if @p value is a JSON Object.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return True if @p value is a JSON Object.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_Create());
+ * PARCJSONValue *value = parcJSONValue_CreateFromJSON(json);
+ * parcJSON_Release(&json);
+ *
+ * if (parcJSONValue_IsObject(value)) {
+ * printf("Success!\n");
+ * }
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_CreateFromJSON
+ */
+bool parcJSONValue_IsJSON(const PARCJSONValue *value);
+
+/**
+ * Determine if @p value is a JSON String.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return True if @p value is a JSON String.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *string = parcBuffer_Wrap("Hello", 0, 5);
+ * PARCJSONValue *value = parcJSONValue_CreateFromString(string);
+ * parcBuffer_Release(&string);
+ *
+ * if (parcJSONValue_IsString(value)) {
+ * printf("Success!\n");
+ * }
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_CreateFromString
+ */
+bool parcJSONValue_IsString(const PARCJSONValue *value);
+
+/**
+ * Determine if @p value is a JSON Array.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return True if @p value is a JSON Array.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *array = parcJSONArray_Create();
+ * PARCJSONValue *value = parcJSONValue_CreateFromJSONArray(array);
+ * parcJSONArray_Release(&array);
+ *
+ * if (parcJSONValue_IsArray(value)) {
+ * printf("Success!\n");
+ * }
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_CreateFromJSONArray
+ */
+bool parcJSONValue_IsArray(const PARCJSONValue *value);
+
+/**
+ * Get the value of the given `PARCJSONValue` as a {@link PARCJSONArray} instance.
+ *
+ * The value must be a JSON Array.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return A pointer to a `PARCJSONArray` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" [ ]");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ *
+ * PARCJSONArray *array = parcJSONValue_GetArray(value);
+ *
+ * parcJSONValue_Release(&value);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_IsArray
+ */
+PARCJSONArray *parcJSONValue_GetArray(const PARCJSONValue *value);
+
+/**
+ * Get the given value is a `bool`
+ *
+ * The value must be a JSON Array of the type {@link PARCJSONValueType_Boolean}
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return A `bool` representation.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" true");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ *
+ * bool result = parcJSONValue_GetBoolean(value);
+ *
+ * parcJSONValue_Release(&value);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see {link parcJSONValue_IsBoolean}
+ */
+bool parcJSONValue_GetBoolean(const PARCJSONValue *value);
+
+/**
+ * Get the JSON float value is a `long double`
+ *
+ *
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return The value as a C double.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" 3.1415");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ *
+ * long double result = parcJSONValue_GetFloat(value);
+ *
+ * parcJSONValue_Release(&value);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_IsNumber
+ */
+long double parcJSONValue_GetFloat(const PARCJSONValue *value);
+
+/**
+ * Get the given value as an integer.
+ *
+ * The value must be a JSON Number value.
+ * The result must be expressible in a 64-bit integer (`int64_t`).
+ * Overflow is not detected.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return The value as a C `int64_t`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" 31415");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ *
+ * int64_t result = parcJSONValue_GetInteger(value);
+ *
+ * parcJSONValue_Release(&value);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_IsNumber
+ */
+int64_t parcJSONValue_GetInteger(const PARCJSONValue *value);
+
+/**
+ * Get the given value is a null-terminated C string.
+ *
+ * The value must be a JSON Array of the type {@link PARCJSONValueType_String}
+ *
+ * A new reference to the return value is not created.
+ * The caller must create a new reference, if it retains a reference to the buffer.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return A pointer to a {@link PARCBuffer} instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" \"a string\"");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ *
+ * PARCBuffer *result = parcJSONValue_GetString(value);
+ *
+ * parcJSONValue_Release(&value);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_IsString
+ */
+PARCBuffer *parcJSONValue_GetString(const PARCJSONValue *value);
+
+/**
+ * Get the value of a JSON object.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ *
+ * @return The value as a pointer to a {@link PARCJSON} instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : \"a string\" }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ *
+ * PARCJSON *result = parcJSONValue_GetJSON(value);
+ *
+ * parcJSONValue_Release(&value);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_IsJSON
+ */
+PARCJSON *parcJSONValue_GetJSON(const PARCJSONValue *value);
+
+/**
+ * Convenience function to fill a timeval struct from a PARCJSONValue.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ * @param [out] timeval A pre-allocated timeval struct to fill.
+ *
+ * @return A pointer to the filled timeval struct.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"seconds\" : 10, \"micros\" : 0 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * parcBuffer_Release(&buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ * parcJSONParser_Release(&parser);
+ *
+ * struct timeval timeval;
+ * parcJSONValue_GetTimeval(value, &timeval);
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ */
+struct timeval *parcJSONValue_GetTimeval(const PARCJSONValue *value, struct timeval *timeval);
+
+/**
+ * Convenience function to fill a timespec struct from a PARCJSONValue.
+ *
+ * @param [in] value A pointer to a `JSONValue` instance.
+ * @param [out] timespec A pre-allocated timespec struct to fill.
+ *
+ * @return A pointer to the filled timespec struct.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"seconds\" : 10, \"nanos\" : 0 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * parcBuffer_Release(&buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ * parcJSONParser_Release(&parser);
+ *
+ * struct timespec timespec;
+ * parcJSONValue_GetTimespec(value, &timespec);
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ */
+struct timespec *parcJSONValue_GetTimespec(const PARCJSONValue *value, struct timespec *timespec);
+
+/**
+ * Create a NULL JSON value.
+ *
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ *
+ */
+PARCJSONValue *parcJSONValue_CreateFromNULL(void);
+
+/**
+ * Create a boolean value.
+ *
+ * @param [in] value Either `true` or `false.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromBoolean(true);
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONValue_CreateFromBoolean(bool value);
+
+/**
+ * Create a float value.
+ *
+ * The resulting PARCJSONValue is a number (see {@link parcJSONValue_IsNumber}).
+ *
+ * @param [in] value A `long double` value.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromFloat(3.14);
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONValue_CreateFromFloat(long double value);
+
+/**
+ * Create a JSON integer value.
+ *
+ * The resulting PARCJSONValue is a number (see {@link parcJSONValue_IsNumber} ).
+ *
+ * @param [in] integer An `int64_t` value.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromInteger(3);
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONValue_CreateFromInteger(int64_t integer);
+
+/**
+ * Create a string value from the contents of a {@link PARCBuffer}.
+ *
+ * @param [in] string A pointer to a `PARCBuffer` instance.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *string = parcBuffer_AllocateCString("hello"):
+ * PARCJSONValue *value = parcJSONValue_CreateFromString(string);
+ *
+ * parcJSONValue_Release(&value);
+ * parcBuffer_Release(&string);
+ * }
+ * @endcode
+ * @see parcJSONValue_CreateFromCString
+ */
+PARCJSONValue *parcJSONValue_CreateFromString(PARCBuffer *string);
+
+/**
+ * Create a string value from a null-terminated C string.
+ *
+ * @param [in] string A pointer to a {@link PARCBuffer} instance.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *value = parcJSONValue_CreateFromCString("hello");
+ *
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ * @see parcJSONValue_CreateFromString
+ */
+PARCJSONValue *parcJSONValue_CreateFromCString(const char *string);
+
+/**
+ * Create a JSON Array value.
+ *
+ * @param [in] array A pointer to a {@link PARCJSONArray} instance.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONArray *array = parcJSONArray_Create();
+ * PARCJSONValue *value = parcJSONValue_CreateFromPARCArray(array);
+ *
+ * PARCJSONArray_Release(&array);
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONValue_CreateFromJSONArray(PARCJSONArray *array);
+
+/**
+ * Create a JSON Value containing a JSON Object.
+ *
+ * A new reference to the given {@link PARCJSON} instance is acquired.
+ *
+ * @param [in] json A pointer to a `PARCJSON` instance.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSON *json = parcJSON_Create();
+ * PARCJSONValue *value = parcJSONValue_CreateFromJSON(json);
+ *
+ * parcJSON_Release(&json);
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONValue_CreateFromJSON(PARCJSON *json);
+
+/**
+ * A convenience function to create a JSON Value containing a JSON Object representing a timeval.
+ *
+ * A new reference to the given {@link PARCJSON} instance is acquired. The json keys for the
+ * timespec fields are are "seconds" & "micros".
+ *
+ * @param [in] timeval A pointer to a timeval instance.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval timeval = { .tv_sec = 1, .tv_usec = 1 };
+ * PARCJSONValue *value = parcJSONValue_CreateFromTimeval(&timeval);
+ *
+ * parcJSON_Release(&json);
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONValue_CreateFromTimeval(const struct timeval *timeval);
+
+/**
+ * A convenience function to create a JSON Value containing a JSON Object representing a timespec.
+ *
+ * A new reference to the given {@link PARCJSON} instance is acquired. The json keys for the
+ * timespec fields are are "seconds" & "nanos".
+ *
+ * @param [in] timeval A pointer to a timespec instance.
+ * @return A pointer to the new `PARCJSONValue`.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timespec timespec = { .tv_sec = 10, .tv_nsec = 0 };
+ * PARCJSONValue *value = parcJSONValue_CreateFromTimespec(&timespec);
+ *
+ * parcJSON_Release(&json);
+ * parcJSONValue_Release(&value);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONValue_CreateFromTimespec(const struct timespec *timespec);
+
+/**
+ * Increase the number of references to a `PARCJSONValue`.
+ *
+ * Note that new `PARCJSONValue` is not created,
+ * only that the given `PARCJSONValue` reference count is incremented.
+ * Discard the reference by invoking {@link parcJSONValue_Release}.
+ *
+ * @param [in] value A pointer to the original instance.
+ *
+ * @return The value of the input parameter @p value.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *x = parcJSONValue_CreateFromNull();
+ *
+ * PARCJSONValue *x2 = parcJSONValue_Acquire(x);
+ *
+ * parcJSONValue_Release(&x);
+ * parcJSONValue_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_Release
+ */
+PARCJSONValue *parcJSONValue_Acquire(const PARCJSONValue *value);
+
+/**
+ * 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.
+ *
+ * The contents of the dealloced memory used for the PARC object are undefined.
+ * Do not reference the object after the last release.
+ *
+ * @param [in,out] valuePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *x = parcJSONValue_CreateFromNull();
+ *
+ * parcJSONValue_Release(&x);
+ * }
+ * @endcode
+ */
+void parcJSONValue_Release(PARCJSONValue **valuePtr);
+
+/**
+ * Determine if two `PARCJSONValue` instances are equal.
+ *
+ *
+ * The following equivalence relations on non-null `PARCJSONValue` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcJSONValue_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcJSONValue_Equals(x, y)` must return true if and only if
+ * `parcJSONValue_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcJSONValue_Equals(x, y)` returns true and
+ * `parcJSONValue_Equals(y, z)` returns true,
+ * then `parcJSONValue_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcJSONValue_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcJSONValue_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] x A pointer to a `PARCJSONValue` instance.
+ * @param [in] y A pointer to a `PARCJSONValue` instance.
+ * @return true if the two `PARCJSONValue` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCJSONValue *x = parcJSONValue_CreateFromBoolean(true);
+ * PARCJSONValue *y = parcJSONValue_CreateFromBoolean(true);
+ *
+ * if (parcJSONValue_Equals(x, y)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool parcJSONValue_Equals(const PARCJSONValue *x, const PARCJSONValue *y);
+
+/**
+ * Produce a null-terminated string representation of the specified instance of `PARCJSONValue`.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] value A pointer to the `PARCJSONValue` 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
+ * {
+ * PARCJSONValue *instance = parcJSONValue_CreateFromString("Hello World");
+ *
+ * char *string = parcJSONValue_ToString(instance);
+ *
+ * if (string != NULL) {
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * parcJSONValue_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_BuildString
+ * @see parcJSONValue_Display
+ */
+char *parcJSONValue_ToString(const PARCJSONValue *value);
+
+/**
+ * Produce a null-terminated "compact" (minimal escaping and formatting) string representation
+ * of the specified instance of `PARCJSONValue`.
+ *
+ * The non-null result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] value A pointer to the `PARCJSONValue` 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
+ * {
+ * PARCJSONValue *instance = parcJSONValue_CreateFromString("Hello World");
+ *
+ * char *string = parcJSONValue_ToCompactString(instance);
+ *
+ * if (string != NULL) {
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ * } else {
+ * printf("Cannot allocate memory\n");
+ * }
+ *
+ * parcJSONValue_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_BuildString
+ * @see parcJSONValue_Display
+ */
+char *parcJSONValue_ToCompactString(const PARCJSONValue *value);
+
+/**
+ * Append a representation of the specified instance to the given
+ * {@link PARCBufferComposer}.
+ *
+ * @param [in] value A pointer to a {@link PARCJSONParser} instance.
+ * @param [in,out] composer A pointer to the {@link PARCBufferComposer} instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The given `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * parcJSONValue_BuildString(instance, result);
+ *
+ * PARCBuffer *string = parcBufferComposer_FinalizeBuffer(result);
+ * printf("JSON Value: %s\n", parcBuffer_ToString(string));
+ * parcBuffer_Release(&string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcJSONValue_BuildString(const PARCJSONValue *value, PARCBufferComposer *composer, bool compact);
+
+/**
+ * Parse an arbitrary JSON value.
+ *
+ * The value may be any valid JSON value, consisting of strings, numbers, objects, arrays, `true`, `false`, or `null`
+ * in their properly encoded string format.
+ *
+ * @param [in] parser A pointer to a {@link PARCJSONParser} instance.
+ *
+ * @return non-NULL A pointer to a valid `PARCJSONValue` instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" 123");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONValue *value = parcJSONValue_Parser(parser);
+ *
+ * parcJSONValue_Release(&value);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ *
+ * @see parcJSONValue_NumberParser
+ */
+PARCJSONValue *parcJSONValue_Parser(PARCJSONParser *parser);
+
+
+/**
+ * Parse a JSON Object value.
+ *
+ * @param [in] parser A pointer to a {@link PARCJSONParser} instance.
+ *
+ * @return non-NULL A pointer to a valid `PARCJSONValue` instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_WrapCString(" { \"name\" : 123 }");
+ *
+ * PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ * PARCJSONValue *value = parcJSONValue_ObjectParser(parser);
+ *
+ * parcJSONValue_Release(&value);
+ * parcJSONParser_Release(&parser);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCJSONValue *parcJSONValue_ObjectParser(PARCJSONParser *parser);
+#endif // libparc_parc_JSONValue_h
diff --git a/libparc/parc/algol/parc_KeyValue.c b/libparc/parc/algol/parc_KeyValue.c
new file mode 100755
index 00000000..27b20f35
--- /dev/null
+++ b/libparc/parc/algol/parc_KeyValue.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 <string.h>
+
+#include "parc_KeyValue.h"
+#include "parc_Object.h"
+
+#include <LongBow/runtime.h>
+
+struct parc_key_value {
+ PARCObject *key;
+ PARCObject *value;
+};
+
+static void
+_parcKeyValue_Destroy(PARCKeyValue **keyValuePointer)
+{
+ PARCKeyValue *keyValue = *keyValuePointer;
+ parcObject_Release(&keyValue->key);
+ if (keyValue->value != NULL) {
+ parcObject_Release(&keyValue->value);
+ }
+}
+
+parcObject_ExtendPARCObject(PARCKeyValue, _parcKeyValue_Destroy, parcKeyValue_Copy, NULL, parcKeyValue_Equals,
+ parcKeyValue_Compare, parcKeyValue_HashCode, NULL);
+
+parcObject_ImplementAcquire(parcKeyValue, PARCKeyValue);
+
+parcObject_ImplementRelease(parcKeyValue, PARCKeyValue);
+
+PARCKeyValue *
+parcKeyValue_Create(const PARCObject *key,
+ const PARCObject *value)
+{
+ assertNotNull(key, "Key may not be null in a KeyValue element");
+
+ PARCKeyValue *keyValue = parcObject_CreateInstance(PARCKeyValue);
+ assertNotNull(keyValue, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCKeyValue));
+
+ keyValue->key = parcObject_Acquire(key);
+ keyValue->value = NULL;
+ if (value != NULL) {
+ keyValue->value = parcObject_Acquire(value);
+ }
+
+ return keyValue;
+}
+
+PARCKeyValue *
+parcKeyValue_Copy(const PARCKeyValue *source)
+{
+ PARCKeyValue *newKV = parcObject_CreateInstance(PARCKeyValue);
+ newKV->key = parcObject_Copy(source->key);
+ newKV->value = NULL;
+ if (source->value != NULL) {
+ newKV->value = parcObject_Copy(source->value);
+ }
+
+ return newKV;
+}
+
+void
+parcKeyValue_SetValue(PARCKeyValue *keyValue, PARCObject *value)
+{
+ assertNotNull(keyValue, "Not a valid keyValue");
+ PARCObject *oldValue = keyValue->value;
+ if (value != NULL) {
+ keyValue->value = parcObject_Acquire(value);
+ } else {
+ keyValue->value = NULL;
+ }
+ if (oldValue != NULL) {
+ parcObject_Release(&oldValue);
+ }
+}
+
+void
+parcKeyValue_SetKey(PARCKeyValue *keyValue, PARCObject *key)
+{
+ assertNotNull(keyValue, "Not a valid keyValue");
+ PARCObject *oldKey = keyValue->key;
+ keyValue->key = parcObject_Acquire(key);
+ parcObject_Release(&oldKey);
+}
+
+PARCObject *
+parcKeyValue_GetValue(PARCKeyValue *keyValue)
+{
+ assertNotNull(keyValue, "Not a valid keyValue");
+ return keyValue->value;
+}
+
+PARCObject *
+parcKeyValue_GetKey(PARCKeyValue *keyValue)
+{
+ assertNotNull(keyValue, "Not a valid keyValue");
+ return keyValue->key;
+}
+
+bool
+parcKeyValue_Equals(const PARCKeyValue *a, const PARCKeyValue *b)
+{
+ bool result = parcObject_Equals(a->key, b->key);
+ if ((a->value == NULL) || (b->value == NULL)) {
+ result &= (a->value == b->value); // Only true if both are NULL
+ } else {
+ result &= parcObject_Equals(a->value, b->value);
+ }
+ return result;
+}
+
+int
+parcKeyValue_Compare(const PARCKeyValue *a, const PARCKeyValue *b)
+{
+ if (a == NULL && b == NULL) {
+ return 0;
+ }
+ if (a != NULL && b == NULL) {
+ return 1;
+ }
+ if (a == NULL && b != NULL) {
+ return -1;
+ } else {
+ return parcObject_Compare(a->key, b->key);
+ }
+}
+
+PARCHashCode
+parcKeyValue_HashCode(const PARCKeyValue *keyValue)
+{
+ return parcObject_HashCode(keyValue->key);
+}
+
+bool
+parcKeyValue_EqualKeys(const PARCKeyValue *a, const PARCKeyValue *b)
+{
+ return parcObject_Equals(a->key, b->key);
+}
diff --git a/libparc/parc/algol/parc_KeyValue.h b/libparc/parc/algol/parc_KeyValue.h
new file mode 100755
index 00000000..a4bc3915
--- /dev/null
+++ b/libparc/parc/algol/parc_KeyValue.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_KeyValue.h
+ * @ingroup datastructures
+ * @brief A key and value tuple.
+ *
+ * The `PARCKeyValue` is a simple key-value tuple.
+ *
+ */
+#ifndef libparc_parc_KeyValue_h
+#define libparc_parc_KeyValue_h
+
+#include "parc_Object.h"
+
+struct parc_key_value;
+
+/**
+ * @typedef `PARCKeyValue`
+ * @brief A `PARCKeyValue` is a tuple consisting of a key and a value
+ */
+typedef struct parc_key_value PARCKeyValue;
+
+/**
+ * Create a `PARCKeyValue` Element. The key and value must be PARCObjects.
+ *
+ * Neither the data nor the key will be copied, but referenced.
+ * The key may not be `NULL`.
+ *
+ * @param [in] key A pointer to the key data
+ * @param [in] value A pointer to the value data
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ * PARCKeyValue *kv = parcKeyValue_Create(key, value);
+ * ...
+ * parcKeyValue_Release(&kv);
+ * }
+ * @endcode
+ */
+PARCKeyValue *parcKeyValue_Create(const PARCObject *key,
+ const PARCObject *value);
+
+/**
+ * Create a copy of a `PARCKeyValue` Element.
+ *
+ * The source PARCKeyValue may not be `NULL`.
+ *
+ * @param [in] keyValue Source PARCKeyValue element
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ * PARCKeyValue *keyValueCopy = parcKeyValue_Copy(sourcKeyValue);
+ * ...
+ * parcKeyValue_Release(&keyValueCopy);
+ * }
+ * @endcode
+ */
+PARCKeyValue *parcKeyValue_Copy(const PARCKeyValue *keyValue);
+
+/**
+ * Acquire a reference to a `PARCKeyValue` Element.
+ *
+ * The source PARCKeyValue may not be `NULL`.
+ *
+ * @param [in] keyValue Source PARCKeyValue element
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ * PARCKeyValue *keyValue = parcKeyValue_Acquire(sourcKeyValue);
+ * ...
+ * parcKeyValue_Release(&keyValue);
+ * }
+ * @endcode
+ */
+PARCKeyValue *parcKeyValue_Acquire(const PARCKeyValue *keyValue);
+
+/**
+ * Release a `PARCKeyValue`.
+ *
+ * Releases a reference to a PARCKeyValue element, if it is the last reference then the
+ * contained key & value objects are released and the elements memory is freed.
+ *
+ * @param [in,out] keyValuePointer A pointer to the pointer to the `PARCKeyValue` to be released
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *kv = parcKeyValue_Create(key, value);
+ * ...
+ * parcKeyValue_Release(&kv);
+ * @endcode
+ */
+void parcKeyValue_Release(PARCKeyValue **keyValuePointer);
+
+/**
+ * Set the value for a `PARCKeyValue`.
+ * The previous value will be released.
+ *
+ * @param [in,out] keyValue A pointer to the keyValue
+ * @param [in] value A pointer to the new value
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *kv = parcKeyValue_Create(key, value);
+ * ...
+ * parcKeyValue_SetKey(kv, newKey);
+ * ...
+ * parcKeyValue_Release(&kv);
+ * @endcode
+ */
+void parcKeyValue_SetValue(PARCKeyValue *keyValue, PARCObject *value);
+
+/**
+ * Set the key for a `PARCKeyValue`.
+ * The previous key will be released.
+ *
+ * @param [in,out] keyValue A pointer to the `PARCKeyValue`
+ * @param [in] key A pointer to the new key
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *kv = parcKeyValue_Create(key, value);
+ * ...
+ * parcKeyValue_SetValue(kv, newValue);
+ * ...
+ * parcKeyValue_Release(&kv);
+ * @endcode
+ */
+void parcKeyValue_SetKey(PARCKeyValue *keyValue, PARCObject *key);
+
+/**
+ * Get the value pointer for the `PARCKeyValue`. No extra reference is created.
+ *
+ * @param [in] keyValue A pointer to the `PARCKeyValue`
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *kv = parcKeyValue_Create(key, value);
+ * ...
+ * PARCObject *value = parcKeyValue_GetValue(kv);
+ * ...
+ * parcKeyValue_Release(&kv);
+ * @endcode
+ */
+PARCObject *parcKeyValue_GetValue(PARCKeyValue *keyValue);
+
+/**
+ * Get the key pointer for the `PARCKeyValue`. No extra reference is created.
+ *
+ * @param [in] keyValue A pointer to the `PARCKeyValue`
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *kv = parcKeyValue_Create(key, value);
+ * ...
+ * PARCObject *key = parcKeyValue_GetKey(kv);
+ * ...
+ * parcKeyValue_Release(&kv);
+ * @endcode
+ */
+PARCObject *parcKeyValue_GetKey(PARCKeyValue *keyValue);
+
+/**
+ * Check for Key equality. Return true if equal.
+ *
+ * @param [in] keyValue1 A pointer to the first `PARCKeyValue`
+ * @param [in] keyValue2 A pointer to the second `PARCKeyValue`
+ * @return true if the keyValues have the same key
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *kv1 = parcKeyValue_Create(key1, value);
+ * PARCKeyValue *kv2 = parcKeyValue_Create(key2, value);
+ * ...
+ * if (parcKeyValue_EqualKeys(kv1, kv2)) {
+ * ...
+ * }
+ * ...
+ * parcKeyValue_Release(&kv1);
+ * parcKeyValue_Release(&kv2);
+ * @endcode
+ */
+bool parcKeyValue_EqualKeys(const PARCKeyValue *keyValue1, const PARCKeyValue *keyValue2);
+
+/**
+ * Check for element equality. Return true if both key & value are equal.
+ *
+ * @param [in] keyValue1 A pointer to the first `PARCKeyValue`
+ * @param [in] keyValue2 A pointer to the second `PARCKeyValue`
+ * @return true if the keys & values both have the same value
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *kv1 = parcKeyValue_Create(key1, value);
+ * PARCKeyValue *kv2 = parcKeyValue_Create(key2, value);
+ * ...
+ * if (parcKeyValue_Equals(kv1, kv2)) {
+ * ...
+ * }
+ * ...
+ * parcKeyValue_Release(&kv1);
+ * parcKeyValue_Release(&kv2);
+ * @endcode
+ */
+bool parcKeyValue_Equals(const PARCKeyValue *keyValue1, const PARCKeyValue *keyValue2);
+
+/**
+ * Compare PARCKeyValue elements. Return an int result based on key compare only.
+ *
+ * @param [in] keyValue1 A pointer to the first `PARCKeyValue`
+ * @param [in] keyValue2 A pointer to the second `PARCKeyValue`
+ * @return parcObject_Compare(keyValue1->key, keyValue2->key)
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *kv1 = parcKeyValue_Create(key1, value);
+ * PARCKeyValue *kv2 = parcKeyValue_Create(key2, value);
+ * ...
+ * if (parcKeyValue_Compare(kv1, kv2) > 0) {
+ * ...
+ * }
+ * ...
+ * parcKeyValue_Release(&kv1);
+ * parcKeyValue_Release(&kv2);
+ * @endcode
+ */
+int parcKeyValue_Compare(const PARCKeyValue *keyValue1, const PARCKeyValue *keyValue2);
+
+/**
+ * Return the HashCode of the PARCKeyValue key.
+ *
+ * @param [in] keyValue A pointer to the first `PARCKeyValue`
+ * @return parcObject_HashCode(keyValue->key);
+ *
+ * Example:
+ * @code
+ * ...
+ * PARCKeyValue *keyValue = parcKeyValue_Create(key1, value);
+ * ...
+ * PARCHashCode *hashCode = parcKeyValue_HashCode(keyValue);
+ * ...
+ * parcKeyValue_Release(&keyValue);
+ * @endcode
+ */
+PARCHashCode parcKeyValue_HashCode(const PARCKeyValue *keyValue);
+#endif // libparc_parc_KeyValue_h
diff --git a/libparc/parc/algol/parc_KeyedElement.c b/libparc/parc/algol/parc_KeyedElement.c
new file mode 100755
index 00000000..a55de891
--- /dev/null
+++ b/libparc/parc/algol/parc_KeyedElement.c
@@ -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.
+ */
+
+/**
+ *
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_KeyedElement.h>
+#include <parc/algol/parc_Memory.h>
+
+struct parc_keyed_element {
+ size_t keylen;
+ void *key;
+ void *element;
+};
+
+PARCKeyedElement *
+parcKeyedElement_Create(void *data, const void *key, size_t keylen)
+{
+ PARCKeyedElement *keyedElement = parcMemory_Allocate(sizeof(PARCKeyedElement));
+ assertNotNull(keyedElement, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCKeyedElement));
+ keyedElement->element = data;
+ keyedElement->key = parcMemory_Allocate(sizeof(PARCKeyedElement));
+ assertNotNull(keyedElement->key, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCKeyedElement));
+ memcpy(keyedElement->key, key, keylen);
+ keyedElement->keylen = keylen;
+ return keyedElement;
+}
+
+void
+parcKeyedElement_Destroy(PARCKeyedElement **keyedElementPointer)
+{
+ parcMemory_Deallocate((void **) &((*keyedElementPointer)->key));
+ parcMemory_Deallocate((void **) keyedElementPointer);
+ *keyedElementPointer = NULL;
+}
+
+void
+parcKeyedElement_SetData(PARCKeyedElement *keyedElement, void *data)
+{
+ keyedElement->element = data;
+}
+
+void *
+parcKeyedElement_GetData(PARCKeyedElement *keyedElement)
+{
+ return keyedElement->element;
+}
+
+void *
+parcKeyedElement_GetKey(PARCKeyedElement *keyedElement)
+{
+ return keyedElement->key;
+}
+
+size_t
+parcKeyedElement_GetKeyLen(PARCKeyedElement *keyedElement)
+{
+ return keyedElement->keylen;
+}
diff --git a/libparc/parc/algol/parc_KeyedElement.h b/libparc/parc/algol/parc_KeyedElement.h
new file mode 100755
index 00000000..e794360f
--- /dev/null
+++ b/libparc/parc/algol/parc_KeyedElement.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_KeyedElement.h
+ * @ingroup datastructures
+ * @brief A Pointer and a Key
+ * The `PARCKeyedElement` is a simple pointer and key tuple.
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#ifndef libparc_parc_KeyedElement_h
+#define libparc_parc_KeyedElement_h
+
+#include <stdint.h>
+#include <stdlib.h>
+
+struct parc_keyed_element;
+
+/**
+ * A `PARCKeyedElement` is a tuple consisting of an address and a key+len.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef struct parc_keyed_element PARCKeyedElement;
+
+/**
+ * Create a `PARCKeyedElement`. Note that the key will be copied (size keylen) while the data will just be
+ * referenced. The key copy will be released when the KeyedElement is destroyed.
+ *
+ * @param [in] data The data we want to associate with a key.
+ * @param [in] key A pointer to the key data (will be copied).
+ * @param [in] keylen The length of the keydata.
+ * @return The new instance of `PARCKeyedElement`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCKeyedElement *parcKeyedElement_Create(void *data, const void *key, size_t keylen);
+
+/**
+ * Destroy a `PARCKeyedElement`.
+ *
+ * If the Free functions were passed to the constructor they will be called if
+ * not NULL. *
+ * @param [in,out] keyedElementPointer A pointer to the pointer to the `PARCKeyedElement` to be destroyed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcKeyedElement_Destroy(PARCKeyedElement **keyedElementPointer);
+/**
+ * Set the data of a `PARCKeyedElement`.
+ *
+ * @param [in,out] keyedElement The pointer to the `PARCKeyedElement` whose data will be reset to @p data.
+ * @param [in] data The data to put be into @p keyedElement
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcKeyedElement_SetData(PARCKeyedElement *keyedElement, void *data);
+
+/**
+ * Get the data of a `PARCKeyedElement`.
+ *
+ * @param [in] keyedElement The pointer to the `PARCKeyedElement` whose data will be retrieved.
+ * @return A pointer to the retrieved data.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcKeyedElement_GetData(PARCKeyedElement *keyedElement);
+
+/**
+ * Retrieve the key of a `PARCKeyedElement`.
+ *
+ * @param [in] keyedElement A pointer to the `PARCKeyedElement` whose key should be retreieved.
+ *
+ * @return A pointer to the `PARCKeyedElement`'s key.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcKeyedElement_GetKey(PARCKeyedElement *keyedElement);
+
+/**
+ * Return the size of the `PARCKeyedElement`'s key.
+ *
+ * @param [in] keyedElement A pointer to the `PARCKeyedElement` whose key length should be returned.
+ *
+ * @return The length of the retrieved key.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcKeyedElement_GetKeyLen(PARCKeyedElement *keyedElement);
+#endif // libparc_parc_KeyedElement_h
diff --git a/libparc/parc/algol/parc_LinkedList.c b/libparc/parc/algol/parc_LinkedList.c
new file mode 100644
index 00000000..d220e223
--- /dev/null
+++ b/libparc/parc/algol/parc_LinkedList.c
@@ -0,0 +1,705 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <sys/queue.h>
+
+#include <parc/algol/parc_LinkedList.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+static PARCListInterface *PARCLinkedListAsPARCList = &(PARCListInterface) {
+ .Add = (bool (*)(void *, void *))parcLinkedList_Append,
+ .AddAtIndex = (void (*)(void *, int index, PARCObject *))parcLinkedList_InsertAtIndex,
+ .AddCollection = (bool (*)(void *, PARCCollection *))NULL,
+ .AddCollectionAtIndex = (bool (*)(void *, int index, PARCCollection *))NULL,
+ .Clear = (void (*)(void *))NULL,
+ .Contains = (bool (*)(const void *, const PARCObject *))parcLinkedList_Contains,
+ .ContainsCollection = (bool (*)(const void *, const PARCCollection *))NULL,
+ .Copy = (void * (*)(const PARCList *))parcLinkedList_Copy,
+ .Destroy = (void (*)(void **))parcLinkedList_Release,
+ .Equals = (bool (*)(const void *, const void *))parcLinkedList_Equals,
+ .GetAtIndex = (PARCObject * (*)(const void *, size_t))parcLinkedList_GetAtIndex,
+ .HashCode = (PARCHashCode (*)(const void *))parcLinkedList_HashCode,
+ .IndexOf = (size_t (*)(const void *, const PARCObject *element))NULL,
+ .IsEmpty = (bool (*)(const void *))parcLinkedList_IsEmpty,
+ .LastIndexOf = (size_t (*)(void *, const PARCObject *element))NULL,
+ .Remove = (bool (*)(void *, const PARCObject *element))parcLinkedList_Remove,
+ .RemoveAtIndex = (PARCObject * (*)(PARCList *, size_t))parcLinkedList_RemoveAtIndex,
+ .RemoveCollection = (bool (*)(void *, const PARCCollection *))NULL,
+ .RetainCollection = (bool (*)(void *, const PARCCollection *))NULL,
+ .SetAtIndex = (PARCObject * (*)(void *, size_t index, PARCObject *))parcLinkedList_SetAtIndex,
+ .Size = (size_t (*)(const void *))parcLinkedList_Size,
+ .SubList = (PARCList * (*)(const void *, size_t, size_t))NULL,
+ .ToArray = (void** (*)(const void *))NULL,
+};
+
+typedef struct parc_linkedlist_node {
+ PARCObject *object;
+ struct parc_linkedlist_node *previous;
+ struct parc_linkedlist_node *next;
+} _PARCLinkedListNode;
+
+struct parc_linkedlist {
+ _PARCLinkedListNode *head;
+ _PARCLinkedListNode *tail;
+ size_t size;
+};
+
+static inline _PARCLinkedListNode *
+_parcLinkedListNode_getByIndex(const PARCLinkedList *list, size_t index)
+{
+ _PARCLinkedListNode *node = list->head;
+ while (index-- && node != NULL) {
+ node = node->next;
+ }
+ return node;
+}
+
+static inline _PARCLinkedListNode *
+_parcLinkedListNode_getByValue(const PARCLinkedList *list, const PARCObject *value)
+{
+ _PARCLinkedListNode *node = list->head;
+ while (node != NULL && parcObject_Equals(node->object, value) == false) {
+ node = node->next;
+ }
+ return node;
+}
+
+static bool
+_parcLinkedListNode_IsValid(const _PARCLinkedListNode *node)
+{
+ bool result = false;
+
+ if (node != NULL) {
+ if (node->object != NULL) {
+ if (parcObject_IsValid(node->object)) {
+ if (node->previous) {
+ if (node->previous->next == node) {
+ if (parcObject_IsValid(node->previous->object)) {
+ result = true;
+ }
+ }
+ } else {
+ result = true;
+ }
+ if (node->next != NULL) {
+ if (node->next->previous == node) {
+ if (parcObject_IsValid(node->next->object)) {
+ result = true;
+ }
+ }
+ } else {
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static inline _PARCLinkedListNode *
+_parcLinkedListNode_Create(const PARCObject *object, _PARCLinkedListNode *previous, _PARCLinkedListNode *next)
+{
+ _PARCLinkedListNode *result = parcMemory_Allocate(sizeof(_PARCLinkedListNode));
+ if (result != NULL) {
+ result->object = parcObject_Acquire(object);
+ result->next = next;
+ result->previous = previous;
+ }
+
+ return result;
+}
+
+static void
+_parcLinkedListIterator_IsValid(const _PARCLinkedListNode *node)
+{
+ if (node != NULL) {
+ assertTrue(_parcLinkedListNode_IsValid(node), "node is invalid");
+ }
+}
+
+static void
+_parcLinkedListNode_Destroy(PARCLinkedList *list __attribute__((unused)), _PARCLinkedListNode **nodePtr)
+{
+ _PARCLinkedListNode *node = *nodePtr;
+
+ parcObject_Release(&node->object);
+ parcMemory_Deallocate((void **) nodePtr);
+}
+
+static bool
+_parcLinkedList_Destructor(PARCLinkedList **listPtr)
+{
+ PARCLinkedList *list = *listPtr;
+
+ _PARCLinkedListNode *next = NULL;
+
+ for (_PARCLinkedListNode *node = list->head; node != NULL; node = next) {
+ next = node->next;
+ _parcLinkedListNode_Destroy(list, &node);
+ }
+ return true;
+}
+
+static _PARCLinkedListNode *
+_parcLinkedIterator_Init(PARCLinkedList *list __attribute__((unused)))
+{
+ return NULL;
+}
+
+static bool
+_parcLinkedListNode_Fini(PARCLinkedList *list __attribute__((unused)), const _PARCLinkedListNode *node __attribute__((unused)))
+{
+ return true;
+}
+
+static struct parc_linkedlist_node *
+_parcLinkedListNode_Next(PARCLinkedList *list __attribute__((unused)), const _PARCLinkedListNode *node)
+{
+ struct parc_linkedlist_node *result = NULL;
+
+ if (node == NULL) {
+ result = list->head;
+ } else {
+ assertTrue(_parcLinkedListNode_IsValid(node), "node is invalid");
+ trapOutOfBoundsIf(node->next == NULL, "No more elements.");
+ result = node->next;
+ }
+
+ assertTrue(_parcLinkedListNode_IsValid(result), "result is invalid");
+ parcObject_OptionalAssertValid(result->object);
+
+ return result;
+}
+
+static inline PARCObject *
+_parcLinkedListNode_Delete(PARCLinkedList *list, _PARCLinkedListNode *node)
+{
+ PARCObject *result = node->object;
+
+ list->size--;
+
+ if (node == list->head) {
+ list->head = node->next;
+ }
+ if (node == list->tail) {
+ list->tail = node->previous;
+ }
+ if (node->previous) {
+ node->previous->next = node->next;
+ }
+ if (node->next) {
+ node->next->previous = node->previous;
+ }
+
+ parcMemory_Deallocate((void **) &node);
+
+ return result;
+}
+
+static void
+_parcLinkedListNode_Remove(PARCLinkedList *list, _PARCLinkedListNode **nodePtr)
+{
+ parcLinkedList_OptionalAssertValid(list);
+
+ _PARCLinkedListNode *node = *nodePtr;
+
+ if (node != NULL) {
+ *nodePtr = node->previous;
+
+ PARCObject *object = _parcLinkedListNode_Delete(list, node);
+ parcObject_Release(&object);
+
+ parcLinkedList_OptionalAssertValid(list);
+ }
+}
+
+static bool
+_parcLinkedListNode_HasNext(PARCLinkedList *list, const _PARCLinkedListNode *node)
+{
+ bool result = false;
+
+ if (node == NULL) {
+ result = (list->head != NULL);
+ if (result) {
+ assertTrue(_parcLinkedListNode_IsValid(list->head), "node is invalid");
+ }
+ } else {
+ result = node->next != NULL;
+ if (result) {
+ assertTrue(_parcLinkedListNode_IsValid(node->next), "node is invalid");
+ }
+ }
+
+
+ return result;
+}
+
+static void *
+_parcLinkedListNode_Element(PARCLinkedList *list __attribute__((unused)), const _PARCLinkedListNode *node)
+{
+ return node->object;
+}
+
+parcObject_Override(PARCLinkedList, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcLinkedList_Destructor,
+ .copy = (PARCObjectCopy *) parcLinkedList_Copy,
+ .equals = (PARCObjectEquals *) parcLinkedList_Equals,
+ .hashCode = (PARCObjectHashCode *) parcLinkedList_HashCode,
+ .display = (PARCObjectDisplay *) parcLinkedList_Display);
+
+PARCIterator *
+parcLinkedList_CreateIterator(PARCLinkedList *list)
+{
+ PARCIterator *iterator = parcIterator_Create(list,
+ (void *(*)(PARCObject *))_parcLinkedIterator_Init,
+ (bool (*)(PARCObject *, void *))_parcLinkedListNode_HasNext,
+ (void *(*)(PARCObject *, void *))_parcLinkedListNode_Next,
+ (void (*)(PARCObject *, void **))_parcLinkedListNode_Remove,
+ (void *(*)(PARCObject *, void *))_parcLinkedListNode_Element,
+ (void (*)(PARCObject *, void *))_parcLinkedListNode_Fini,
+ (void (*)(const void *))_parcLinkedListIterator_IsValid);
+
+ return iterator;
+}
+
+PARCLinkedList *
+parcLinkedList_Create(void)
+{
+ PARCLinkedList *result = parcObject_CreateInstance(PARCLinkedList);
+
+ if (result != NULL) {
+ result->head = NULL;
+ result->tail = NULL;
+ result->size = 0;
+ }
+ return result;
+}
+
+bool
+parcLinkedList_IsValid(const PARCLinkedList *list)
+{
+ bool result = false;
+
+ if (list != NULL) {
+ if (parcObject_IsValid(list)) {
+ if (list->size > 0) {
+ if (list->head != NULL) {
+ if (list->tail != NULL) {
+ result = true;
+ for (_PARCLinkedListNode *node = list->head; node != NULL; node = node->next) {
+ if (_parcLinkedListNode_IsValid(node) == false) {
+ result = false;
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ if (list->head == NULL) {
+ if (list->tail == NULL) {
+ result = true;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+void
+parcLinkedList_AssertValid(const PARCLinkedList *instance)
+{
+ assertTrue(parcLinkedList_IsValid(instance),
+ "PARCLinkedList is not valid.");
+}
+
+parcObject_ImplementAcquire(parcLinkedList, PARCLinkedList);
+
+parcObject_ImplementRelease(parcLinkedList, PARCLinkedList);
+
+PARCLinkedList *
+parcLinkedList_Copy(const PARCLinkedList *list)
+{
+ PARCLinkedList *result = parcLinkedList_Create();
+
+ struct parc_linkedlist_node *node = list->head;
+
+ while (node != NULL) {
+ parcLinkedList_Append(result, node->object);
+ node = node->next;
+ }
+
+ return result;
+}
+
+bool
+parcLinkedList_Contains(const PARCLinkedList *list, const PARCObject *element)
+{
+ bool result = false;
+
+ struct parc_linkedlist_node *node = list->head;
+
+ while (node != NULL) {
+ if (parcObject_Equals(node->object, element)) {
+ result = true;
+ break;
+ }
+ node = node->next;
+ }
+
+ return result;
+}
+
+PARCLinkedList *
+parcLinkedList_Append(PARCLinkedList *list, const PARCObject *element)
+{
+ _PARCLinkedListNode *node = _parcLinkedListNode_Create(element, list->tail, NULL);
+
+ if (list->tail == NULL) {
+ list->tail = node;
+ } else {
+ list->tail->next = node;
+ list->tail = node;
+ }
+
+ if (list->head == NULL) {
+ list->head = list->tail;
+ }
+
+ list->size++;
+
+ return list;
+}
+
+PARCLinkedList *
+parcLinkedList_AppendAll(PARCLinkedList *list, const PARCLinkedList *other)
+{
+ PARCIterator *iterator = parcLinkedList_CreateIterator((PARCLinkedList *) other);
+ while (parcIterator_HasNext(iterator)) {
+ PARCObject *object = parcIterator_Next(iterator);
+ parcLinkedList_Append(list, object);
+ }
+ parcIterator_Release(&iterator);
+
+ return list;
+}
+
+PARCLinkedList *
+parcLinkedList_Prepend(PARCLinkedList *list, const PARCObject *element)
+{
+ _PARCLinkedListNode *node = _parcLinkedListNode_Create(element, NULL, list->head);
+
+ if (list->head == NULL) {
+ list->head = node;
+ } else {
+ list->head->previous = node;
+ list->head = node;
+ }
+
+ if (list->tail == NULL) {
+ list->tail = list->head;
+ }
+ list->size++;
+
+ parcLinkedList_OptionalAssertValid(list);
+
+ return list;
+}
+
+PARCObject *
+parcLinkedList_RemoveFirst(PARCLinkedList *list)
+{
+ PARCObject *result = NULL;
+
+ if (list->head != NULL) {
+ _PARCLinkedListNode *node = list->head;
+ result = _parcLinkedListNode_Delete(list, node);
+ }
+
+ parcLinkedList_OptionalAssertValid(list);
+
+ return result;
+}
+
+PARCObject *
+parcLinkedList_RemoveLast(PARCLinkedList *list)
+{
+ PARCObject *result = NULL;
+
+ if (list->tail != NULL) {
+ _PARCLinkedListNode *node = list->tail;
+ result = _parcLinkedListNode_Delete(list, node);
+ }
+
+ parcLinkedList_OptionalAssertValid(list);
+ return result;
+}
+
+bool
+parcLinkedList_Remove(PARCLinkedList *list, const PARCObject *element)
+{
+ assertTrue(element != NULL, "Element must not be NULL");
+ bool result = false;
+
+ _PARCLinkedListNode *node = _parcLinkedListNode_getByValue(list, element);
+ if (node != NULL) {
+ PARCObject *e = _parcLinkedListNode_Delete(list, node);
+ parcObject_Release(&e);
+ result = true;
+ }
+
+ parcLinkedList_OptionalAssertValid(list);
+
+ return result;
+}
+
+PARCObject *
+parcLinkedList_RemoveAtIndex(PARCLinkedList *list, size_t index)
+{
+ PARCObject *result = NULL;
+
+ _PARCLinkedListNode *node = _parcLinkedListNode_getByIndex(list, index);
+ if (node != NULL) {
+ result = _parcLinkedListNode_Delete(list, node);
+ }
+
+ return result;
+}
+
+PARCObject *
+parcLinkedList_GetFirst(const PARCLinkedList *list)
+{
+ PARCObject *result = NULL;
+
+ if (list->head != NULL) {
+ _PARCLinkedListNode *node = list->head;
+ result = node->object;
+ }
+ return result;
+}
+
+PARCObject *
+parcLinkedList_GetLast(const PARCLinkedList *list)
+{
+ PARCObject *result = NULL;
+
+ if (list->tail != NULL) {
+ _PARCLinkedListNode *node = list->tail;
+ result = node->object;
+ }
+ return result;
+}
+
+PARCHashCode
+parcLinkedList_HashCode(const PARCLinkedList *list)
+{
+ PARCHashCode result = 0;
+
+ _PARCLinkedListNode *node = list->head;
+ if (node != NULL) {
+ while (node != NULL) {
+ result += parcObject_HashCode(node->object);
+ node = node->next;
+ }
+ }
+
+ return result;
+}
+
+size_t
+parcLinkedList_Size(const PARCLinkedList *list)
+{
+ return list->size;
+}
+
+bool
+parcLinkedList_IsEmpty(const PARCLinkedList *list)
+{
+ return (parcLinkedList_Size(list) == 0);
+}
+
+static void
+_parcLinkedList_InsertInitialNode(PARCLinkedList *list, const PARCObject *element)
+{
+ _PARCLinkedListNode *newNode = _parcLinkedListNode_Create(element, NULL, NULL);
+ list->head = newNode;
+ list->tail = newNode;
+}
+
+PARCLinkedList *
+parcLinkedList_InsertAtIndex(PARCLinkedList *list, size_t index, const PARCObject *element)
+{
+ if (index == 0) {
+ if (list->head == NULL) {
+ _parcLinkedList_InsertInitialNode(list, element);
+ } else {
+ _PARCLinkedListNode *newNode = _parcLinkedListNode_Create(element, NULL, list->head);
+
+ list->head->previous = newNode;
+ list->tail = list->head;
+ list->head = newNode;
+ }
+
+ list->size++;
+ } else if (index == list->size) {
+ _PARCLinkedListNode *node = list->tail;
+ node->next = _parcLinkedListNode_Create(element, node, NULL);
+ list->tail = node->next;
+ list->size++;
+ } else {
+ _PARCLinkedListNode *node = list->head;
+ while (index-- && node->next != NULL) {
+ node = node->next;
+ }
+ _PARCLinkedListNode *newNode = _parcLinkedListNode_Create(element, node->previous, node);
+
+ node->previous->next = newNode;
+ node->previous = newNode;
+ list->size++;
+ }
+
+ parcLinkedList_OptionalAssertValid(list);
+ return list;
+}
+
+PARCObject *
+parcLinkedList_SetAtIndex(PARCLinkedList *list, size_t index, PARCObject *element)
+{
+ PARCObject *result = NULL;
+
+ if (index > (parcLinkedList_Size(list) - 1)) {
+ trapOutOfBounds(index, "[0, %zd]", parcLinkedList_Size(list) - 1);
+ }
+
+ _PARCLinkedListNode *node = _parcLinkedListNode_getByIndex(list, index);
+ if (node != NULL) {
+ result = node->object;
+ node->object = parcObject_Acquire(element);
+ }
+ return result;
+}
+
+PARCObject *
+parcLinkedList_GetAtIndex(const PARCLinkedList *list, size_t index)
+{
+ if (index > (parcLinkedList_Size(list) - 1)) {
+ trapOutOfBounds(index, "[0, %zd]", parcLinkedList_Size(list) - 1);
+ }
+
+ _PARCLinkedListNode *node = _parcLinkedListNode_getByIndex(list, index);
+ return (node == NULL) ? NULL : node->object;
+}
+
+bool
+parcLinkedList_Equals(const PARCLinkedList *x, const PARCLinkedList *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ if (x->size == y->size) {
+ _PARCLinkedListNode *xNode = x->head;
+ _PARCLinkedListNode *yNode = y->head;
+
+ while (xNode != NULL) {
+ if (parcObject_Equals(xNode->object, yNode->object) == false) {
+ return false;
+ }
+ xNode = xNode->next;
+ yNode = yNode->next;
+ }
+ return true;
+ }
+ return false;
+}
+
+void
+parcLinkedList_Display(const PARCLinkedList *list, const int indentation)
+{
+ if (list == NULL) {
+ parcDisplayIndented_PrintLine(indentation, "PARCLinkedList@NULL");
+ } else {
+ parcDisplayIndented_PrintLine(indentation, "PARCLinkedList@%p { .size=%016zp, .head=%016zp, .tail=%016zp",
+ (void *) list, list->size, list->head, list->tail);
+
+ _PARCLinkedListNode *node = list->head;
+
+ while (node != NULL) {
+ parcDisplayIndented_PrintLine(indentation + 1,
+ "%016zp { .previous=%016zp, %016zp, .next=%016zp }",
+ node, node->previous, node->object, node->next);
+ parcObject_Display(node->object, indentation + 2);
+ node = node->next;
+ }
+
+ parcDisplayIndented_PrintLine(indentation, "}\n");
+ }
+}
+
+bool
+parcLinkedList_SetEquals(const PARCLinkedList *x, const PARCLinkedList *y)
+{
+ bool result = false;
+
+ if (x->size == y->size) {
+ for (size_t i = 0; i < x->size; i++) {
+ PARCObject *xObject = parcLinkedList_GetAtIndex(x, i);
+ for (size_t j = 0; j < x->size; j++) {
+ PARCObject *yObject = parcLinkedList_GetAtIndex(y, j);
+ if (parcObject_Equals(xObject, yObject) == false) {
+ break;
+ }
+ }
+ }
+ result = true;
+ }
+
+ return result;
+}
+
+PARCList *
+parcLinkedList_AsPARCList(PARCLinkedList *list)
+{
+ PARCList *result = parcList_Create(list, PARCLinkedListAsPARCList);
+ return result;
+}
+
+void
+parcLinkedList_ApplyImpl(PARCLinkedList *list, void (*function)(PARCObject *, const void *), const void *parameter)
+{
+ PARCIterator *iterator = parcLinkedList_CreateIterator(list);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCObject *object = parcIterator_Next(iterator);
+ function(object, parameter);
+ }
+
+ parcIterator_Release(&iterator);
+}
diff --git a/libparc/parc/algol/parc_LinkedList.h b/libparc/parc/algol/parc_LinkedList.h
new file mode 100644
index 00000000..7babff79
--- /dev/null
+++ b/libparc/parc/algol/parc_LinkedList.h
@@ -0,0 +1,698 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_LinkedList.h
+ * @ingroup datastructures
+ * @brief PARC Double-ended Queue (Deque)
+ *
+ */
+#ifndef libparc_parc_LinkedList_h
+#define libparc_parc_LinkedList_h
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Iterator.h>
+
+struct parc_linkedlist;
+/**
+ * A simple linked list.
+ *
+ * @see {@link parcLinkedList_Create}
+ */
+typedef struct parc_linkedlist PARCLinkedList;
+
+/**
+ * Create a `PARCLinkedList` instance with the default element equality and copy functions.
+ *
+ * The queue is created with no elements.
+ *
+ * The default element equals function is used by the `{@link parcLinkedList_Equals} function and
+ * simply compares the values using the `==` operator.
+ *
+ * @return non-NULL A pointer to a `PARCLinkedList` instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+PARCLinkedList *parcLinkedList_Create(void);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcLinkedList_OptionalAssertValid(_instance_)
+#else
+# define parcLinkedList_OptionalAssertValid(_instance_) parcLinkedList_AssertValid(_instance_)
+#endif
+void parcLinkedList_AssertValid(const PARCLinkedList *list);
+
+/**
+ * Create a new instance of PARCIterator that iterates through the given PARCLinkedList.
+ * The returned value must be released via {@link parcIterator_Release}.
+ *
+ * @param [in] list A pointer to a valid `PARCLinkedList`.
+ *
+ * @see parcIterator_Release
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIterator *iterator = parcLinkedList_CreateIterator(list);
+ *
+ * while (parcIterator_HasNext(iterator)) {
+ * PARCObject *object = parcIterator_Next(iterator);
+ * }
+ *
+ * parcIterator_Release(&iterator);
+ * }
+ * @endcode
+ */
+PARCIterator *parcLinkedList_CreateIterator(PARCLinkedList *list);
+
+/**
+ * Acquire a new reference to an instance of `PARCLinkedList`.
+ *
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] list The instance of `PARCLinkedList` to which to refer.
+ *
+ * @return The same value as the input parameter @p deque
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCLinkedList *parcLinkedList_Acquire(const PARCLinkedList *list);
+
+/**
+ * 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 interface will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] listPtr A pointer to a pointer to the instance of `PARCLinkedList` to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLinkedList *buffer = parcLinkedList_Create(10);
+ *
+ * parcLinkedList_Release(&buffer);
+ * }
+ * @endcode
+ */
+void parcLinkedList_Release(PARCLinkedList **listPtr);
+
+/**
+ * Copy a a `PARCLinkedList` to another.
+ *
+ * @param [in] list A pointer to an instance of `PARCLinkedList`
+ *
+ * @return A pointer to a copy of the original instance of `PARCLinkedList`
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCLinkedList *parcLinkedList_Copy(const PARCLinkedList *list);
+
+/**
+ * Determine if an instance of `PARCLinkedList` 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] list A pointer to a `PARCLinkedList` instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLinkedList *instance = parcLinkedList_Create();
+ *
+ * if (parcLinkedList_IsValid(instance)) {
+ * printf("Instance is valid.\n");
+ * }
+ * }
+ * @endcode
+ */
+bool parcLinkedList_IsValid(const PARCLinkedList *list);
+
+/**
+ * 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 `PARCLinkedList` instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLinkedList *buffer = parcLinkedList_Allocate(10);
+ * PARCHashCode hash = parcLinkedList_HashCode(buffer);
+ * parcLinkedList_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCHashCode parcLinkedList_HashCode(const PARCLinkedList *instance);
+
+/**
+ * Returns true if the given `PARCLinkedList` contains the specified `PARCObject`.
+ *
+ * The semantics are such that the function returns `true` if and only if the `PARCLinkedList`
+ * list contains at least one `PARCObject` _o_ such that PARCObject_Equals(_o_, object) is true.
+ *
+ * @param [in] list A pointer to a valid `PARCLinkedList` instance.
+ * @param [in] object A pointer to a valid `PARCObject` instance.
+ *
+ * @return true The given `PARCLinkedList` contains the specified `PARCObject`.
+ * @return false The given `PARCLinkedList` does not contain the specified `PARCObject`.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcLinkedList_Contains(const PARCLinkedList *list, const PARCObject *object);
+
+/**
+ * Append an element to the tail end of the specified `PARCLinkedList`
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList` to which the element will be appended
+ * @param [in] element A pointer to the element to be appended to the instance of `PARCLinkedList`
+ *
+ * @return non NULL A pointer to the specific instance of `PARCLinkedList`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCLinkedList *parcLinkedList_Append(PARCLinkedList *list, const PARCObject *element);
+
+/**
+ * Append each element from the PARCLinkedList @p other to @p list.
+ *
+ * @param [in] list A pointer to a valid PARCLinkedList instance that will be receive each element from @p other.
+ * @param [in] other A pointer to a valid PARCLinkedList instance containing the elements to append to @p list.
+ *
+ * @return The value of @p list.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCLinkedList *parcLinkedList_AppendAll(PARCLinkedList *list, const PARCLinkedList *other);
+
+/**
+ * Prepend an element to the head end of the specified `PARCLinkedList`
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList` to which the element will be prepended
+ * @param [in] element A pointer to the element to be appended to the instance of `PARCLinkedList`
+ *
+ * @return non NULL A pointer to the specific instance of `PARCLinkedList`
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCLinkedList *parcLinkedList_Prepend(PARCLinkedList *list, const PARCObject *element);
+
+/**
+ * Return the first element of the specified `PARCLinkedList` and remove it from the list.
+ * The element's reference count is not modified,
+ * the caller must release the returned element when it is finished with it.
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList` from which the first element will be returned and removed
+ *
+ * @return non NULL A pointer to the element removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+PARCObject *parcLinkedList_RemoveFirst(PARCLinkedList *list);
+
+/**
+ * Remove the last element in the queue and return it.
+ * The element's reference count is not modified,
+ * the caller must release the returned element when it is finished with it.
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList` from which the last element will be removed and returned.
+ *
+ * @return non-NULL A pointer to the element removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+PARCObject *parcLinkedList_RemoveLast(PARCLinkedList *list);
+
+/**
+ * Remove the first occurrence of the given element from the specified 'PARCLinkedList'.
+ * The element's reference count is decremented.
+ *
+ * @param [in] element the element to remove
+ * @return true if the element was found in the list and successfully removed
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLinkedList *list = parcLinkedList_Create();
+ *
+ * PARCBuffer *buffer = parcBuffer_WrapCString("1");
+ * parcLinkedList_Append(list, buffer);
+ * parcBuffer_Release(&buffer);
+ * // ...
+ * PARCBuffer *actual = parcLinkedList_Remove(list, buffer);
+ * parcBuffer_Release(&actual);
+ *
+ * // ...
+ *
+ * parcLinkedList_Release(&list);
+ * }
+ * @endcode
+ */
+bool parcLinkedList_Remove(PARCLinkedList *list, const PARCObject *element);
+
+/**
+ * Removes the element at the specified position in this list.
+ *
+ * Shifts all subsequent elements to the left (subtracts one from their indices).
+ * Return the element that was removed from the list without modifying the reference count.
+ * The caller must eventually release the returned value.
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList` from which the element will be removed.
+ * @param [in] index The index (origin 0) of the element to remove.
+ *
+ * @return The element that was removed from the list.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLinkedList *list = parcLinkedList_Create();
+ * // add elements to the list.
+ *
+ * parcLinkedList_RemoveAtIndex(list, 2); // remove the 3rd element in the list.
+ *
+ * // ...
+ *
+ * parcLinkedList_Release(&list);
+ * }
+ * @endcode
+ */
+PARCObject *parcLinkedList_RemoveAtIndex(PARCLinkedList *list, size_t index);
+
+/**
+ * Return the first element of the specified `PARCLinkedList` but do NOT remove it from the queue
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList` from which the first element will be returned
+ *
+ * @return non NULL A pointer to the first element
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+PARCObject *parcLinkedList_GetFirst(const PARCLinkedList *list);
+
+/**
+ * Return the last element of the specified `PARCLinkedList` but do NOT remove it from the queue
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList` from which the last element will be returned
+ *
+ * @return non NULL A pointer to the last element
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+PARCObject *parcLinkedList_GetLast(const PARCLinkedList *list);
+
+/**
+ * Return the size of the specified queue
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList`
+ *
+ * @return `size_t` The size of the queue
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+size_t parcLinkedList_Size(const PARCLinkedList *list);
+
+/**
+ * Return True if the `PARCLinkedList` is empty or False if not.
+ *
+ * @param [in] list A pointer to the instance of `PARCLinkedList`
+ *
+ * @return bool True if the `PARCLinkedList` is empty or False if not.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+bool parcLinkedList_IsEmpty(const PARCLinkedList *list);
+
+/**
+ * Get a pointer to the specified element.
+ *
+ * @param [in] list A pointer to a `PARCLinkedList` instance.
+ * @param [in] index The index of the element to be retrieved.
+ *
+ * @throws `trapOutOfBounds`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCObject *parcLinkedList_GetAtIndex(const PARCLinkedList *list, size_t index);
+
+/**
+ * Replace the element at the specified position in this list with the given element.
+ *
+ * @param [in] list A pointer to a `PARCLinkedList` instance.
+ * @param [in] index The index of the element to be replaced.
+ * @param [in] element A pointer to a valid PARCObject instance that will replace the current element at @p index.
+ *
+ * @throws `trapOutOfBounds`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCObject *parcLinkedList_SetAtIndex(PARCLinkedList *list, size_t index, PARCObject *element);
+
+/**
+ * Determine if two `PARCLinkedList` instances are equal.
+ *
+ * This function implements the following equivalence relations on non-null `PARCLinkedList` instances:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcLinkedList_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcLinkedList_Equals(x, y)` must return true if and only if
+ * `parcLinkedList_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcLinkedList_Equals(x, y)` returns true and
+ * `parcLinkedList_Equals(y, z)` returns true,
+ * then `parcLinkedList_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcLinkedList_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcLinkedList_Equals(x, NULL)` must return false.
+ *
+ * Two `PARCLinkedList` instances with different element equality functions are always unequal.
+ *
+ * @param [in] x A pointer to a `PARCLinkedList` instance.
+ * @param [in] y A pointer to a `PARCLinkedList` instance.
+ *
+ * @return true `PARCLinkedList` x and y are equal.
+ * @return false `PARCLinkedList` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcLinkedList_Equals(const PARCLinkedList *x, const PARCLinkedList *y);
+
+/**
+ * Print a human readable representation of the given `PARCLinkedList`.
+ *
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ * @param [in] list A pointer to the instance to display.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLinkedList *instance = parcLinkedList_Create();
+ *
+ * parcLinkedList_Display(instance, 0);
+ *
+ * parcLinkedList_Release(&instance);
+ * }
+ * @endcode
+ *
+ */
+void parcLinkedList_Display(const PARCLinkedList *list, int indentation);
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcLinkedList_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] object A pointer to a valid PARCLinkedList instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcLinkedList_Notify(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotify(parcLinkedList, PARCLinkedList);
+
+/**
+ * Wakes up all threads that are waiting on the given object's lock.
+ *
+ * A thread waits on an object by calling one of the wait methods, `parcLinkedList_Wait`, `parcLinkedList_WaitFor`, `parcLinkedList_WaitUntil`.
+ * The awakened threads will proceed after the current thread relinquishes the lock on the given object.
+ * The awakened threads will compete in the usual manner with any other threads that might be actively competing
+ * to synchronize on this object.
+ * Awakened threads have no priority between them in being the next thread to lock this object.
+ *
+ * This method can only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid `PARCLinkedList` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcLinkedList_Lock(object)) {
+ * parcLinkedList_NotifyAll(object);
+ * parcLinkedList_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotifyAll(parcLinkedList, PARCLinkedList);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the parcLinkedList_Notify() function on the same object.
+ *
+ * @param [in] object A pointer to a valid `PARCLinkedList` instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcLinkedList_Wait(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementWait(parcLinkedList, PARCLinkedList);
+
+parcObject_ImplementWaitFor(parcLinkedList, PARCLinkedList);
+
+parcObject_ImplementWaitUntil(parcLinkedList, PARCLinkedList);
+
+/**
+ * Obtain the lock on the given `PARCLinkedList` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] object A pointer to a valid `PARCLinkedList` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, or the `PARCLinkedList` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcLinkedList_Lock(object)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementLock(parcLinkedList, PARCLinkedList);
+
+/**
+ * Try to obtain the advisory lock on the given PARCLinkedList instance.
+ *
+ * Once the lock is obtained, the caller must release the lock as soon as possible.
+ *
+ * @param [in] object A pointer to a valid PARCLinkedList instance.
+ *
+ * @return true The PARCLinkedList is locked.
+ * @return false The PARCLinkedList is unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcLinkedList_TryLock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementTryLock(parcLinkedList, PARCLinkedList);
+
+/**
+ * Try to unlock the advisory lock on the given `PARCLinkedList` instance.
+ *
+ * @param [in] object A pointer to a valid `PARCLinkedList` instance.
+ *
+ * @return true The `PARCLinkedList` was locked and now is unlocked.
+ * @return false The `PARCLinkedList` was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcLinkedList_Unlock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementUnlock(parcLinkedList, PARCLinkedList);
+
+/**
+ * Determine if the advisory lock on the given `PARCLinkedList` instance is locked.
+ *
+ * @param [in] object A pointer to a valid `PARCLinkedList` instance.
+ *
+ * @return true The `PARCLinkedList` is locked.
+ * @return false The `PARCLinkedList` is unlocked.
+ * Example:
+ * @code
+ * {
+ * if (parcLinkedList_IsLocked(object)) {
+ * ...
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementIsLocked(parcLinkedList, PARCLinkedList);
+
+/**
+ * Determine if two `PARCLinkedList` instances are equivalent sets.
+ *
+ * The lists are examined without regard to order.
+ * If both lists, x and y are of equal length, and all of the elements in list `x` are present in list `y`, this function returns true.
+ *
+ * @param [in] x A pointer to a valid `PARCLinkedList` instance.
+ * @param [in] y A pointer to a valid `PARCLinkedList` instance.
+ * @return true The instances are equivalent.
+ * @return false The instances are equivalent.
+ *
+ */
+bool parcLinkedList_SetEquals(const PARCLinkedList *x, const PARCLinkedList *y);
+
+/**
+ * Insert the given element into the list such that it is the index'th element in the list.
+ */
+PARCLinkedList *parcLinkedList_InsertAtIndex(PARCLinkedList *list, size_t index, const PARCObject *element);
+
+/**
+ * Apply a function to every element in the given PARCLinkedList.
+ *
+ * The function is applied in order, any return value is ignored.
+ *
+ * @param [in] list A pointer to a valid PARCLinkedList instance.
+ * @param [in] function A pointer to a function that will be called with each element of the list.
+ * @param [in] parameter A pointer to arbitrary data that will supplied as an additional parameter to @p function
+ *
+ */
+#define parcLinkedList_Apply(_list_, _function_, _parameter_) \
+ parcLinkedList_ApplyImpl(_list_, (void (*))_function_, (const void *) _parameter_)
+void parcLinkedList_ApplyImpl(PARCLinkedList *list, void (*function)(PARCObject *, const void *), const void *parameter);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCList *parcLinkedList_AsPARCList(PARCLinkedList *list);
+#endif // libparc_parc_Deque_h
diff --git a/libparc/parc/algol/parc_List.c b/libparc/parc/algol/parc_List.c
new file mode 100644
index 00000000..0e62cda6
--- /dev/null
+++ b/libparc/parc/algol/parc_List.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <stdarg.h>
+
+#include <parc/algol/parc_Object.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Memory.h>
+
+struct parc_list {
+ void *instance;
+ const PARCListInterface *interface;
+};
+
+static void
+_destroy(PARCList **listPtr)
+{
+ PARCList *list = *listPtr;
+
+ (list->interface->Destroy)(&list->instance);
+}
+
+parcObject_ExtendPARCObject(PARCList, _destroy, parcList_Copy, NULL, parcList_Equals, NULL, parcList_HashCode, NULL);
+
+PARCList *
+parcList(void *instance, PARCListInterface *interface)
+{
+ PARCList *result = parcObject_CreateInstance(PARCList);
+ if (result != NULL) {
+ result->instance = instance;
+ result->interface = interface;
+ }
+
+ return result;
+}
+
+PARCList *
+parcList_Create(PARCObject *instance, PARCListInterface *interface)
+{
+ PARCList *result = parcObject_CreateInstance(PARCList);
+ if (result != NULL) {
+ result->instance = parcObject_Acquire(instance);
+ result->interface = interface;
+ }
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcList, PARCList);
+
+parcObject_ImplementRelease(parcList, PARCList);
+
+PARCList *
+parcList_Copy(const PARCList *list)
+{
+ PARCList *result = parcObject_CreateInstance(PARCList);
+ if (result != NULL) {
+ result->instance = (list->interface->Copy)(list->instance);
+ result->interface = list->interface;
+ }
+
+ return result;
+}
+
+bool
+parcList_IsEmpty(const PARCList *list)
+{
+ bool result = false;
+ if (list->interface->IsEmpty) {
+ result = (list->interface->IsEmpty)(list->instance);
+ } else {
+ result = (parcList_Size(list) == 0);
+ }
+ return result;
+}
+
+bool
+parcList_Add(PARCList *list, void *element)
+{
+ return (list->interface->Add)(list->instance, element);
+}
+
+bool
+parcList_AddAll(PARCList *list, size_t argc, void *argv[argc])
+{
+ for (int i = 0; i < argc; i++) {
+ (list->interface->Add)(list->instance, argv[i]);
+ }
+ return true;
+}
+
+void
+parcList_AddAtIndex(PARCList *list, int index, void *element)
+{
+ (list->interface->AddAtIndex)(list->instance, index, element);
+}
+
+bool
+parcList_AddCollection(PARCList *list, PARCCollection *collection)
+{
+ return (list->interface->AddCollection)(list->instance, collection);
+}
+
+bool
+parcList_AddCollectionAtIndex(PARCList *list, int index, PARCCollection *collection)
+{
+ return (list->interface->AddCollectionAtIndex)(list->instance, index, collection);
+}
+
+void
+parcList_Clear(PARCList *list)
+{
+ if (!list->interface->Clear) {
+ for (size_t i = 0; i < parcList_Size(list); i++) {
+ parcList_RemoveAtIndex(list, i);
+ }
+ } else {
+ (list->interface->Clear)(list->instance);
+ }
+}
+
+bool
+parcList_Contains(const PARCList *list, void *element)
+{
+ return (list->interface->Contains)(list->instance, element);
+}
+
+bool
+parcList_ContainsCollection(PARCList *list, PARCCollection *collection)
+{
+ return (list->interface->ContainsCollection)(list->instance, collection);
+}
+
+bool
+parcList_Equals(const PARCList *x, const PARCList *y)
+{
+ return (x->interface->Equals)(x->instance, y->instance);
+}
+
+void *
+parcList_GetAtIndex(const PARCList *list, size_t index)
+{
+ return (list->interface->GetAtIndex)(list->instance, index);
+}
+
+int
+parcList_HashCode(const PARCList *list)
+{
+ return (list->interface->HashCode)(list->instance);
+}
+
+ssize_t
+parcList_IndexOf(const PARCList *list, PARCObject *element)
+{
+ ssize_t result = -1;
+
+ if (list->interface->IndexOf) {
+ result = (list->interface->IndexOf)(list->instance, element);
+ } else {
+ for (ssize_t i = 0; i < parcList_Size(list); i++) {
+ PARCObject *e = parcList_GetAtIndex(list, i);
+ if (parcObject_Equals(e, element)) {
+ result = i;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+ssize_t
+parcList_LastIndexOf(const PARCList *list, PARCObject *element)
+{
+ ssize_t result = -1;
+
+ if (list->interface->LastIndexOf) {
+ result = (list->interface->LastIndexOf)(list->instance, element);
+ } else {
+ for (ssize_t i = parcList_Size(list) - 1; i >= 0; i--) {
+ PARCObject *e = parcList_GetAtIndex(list, i);
+ if (parcObject_Equals(e, element)) {
+ result = i;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCObject *
+parcList_RemoveAtIndex(PARCList *list, size_t index)
+{
+ if (list->interface->RemoveAtIndex) {
+ return (list->interface->RemoveAtIndex)(list->instance, index);
+ } else {
+ return NULL;
+ }
+}
+
+bool
+parcList_Remove(PARCList *list, PARCObject *element)
+{
+ bool result = false;
+
+ if (list->interface->Remove != NULL) {
+ result = (list->interface->Remove)(list->instance, element);
+ } else {
+ for (size_t i = 0; i < parcList_Size(list); i++) {
+ void *e = parcList_GetAtIndex(list, i);
+ if (parcObject_Equals(e, element)) {
+ parcList_RemoveAtIndex(list, i);
+ result = true;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+bool
+parcList_RemoveCollection(PARCList *list, PARCCollection *collection)
+{
+ return (list->interface->RemoveCollection)(list->instance, collection);
+}
+
+bool
+parcList_RetainCollection(PARCList *list, PARCCollection *collection)
+{
+ return (list->interface->RetainCollection)(list->instance, collection);
+}
+
+PARCObject *
+parcList_SetAtIndex(PARCList *list, size_t index, void *element)
+{
+ return (list->interface->SetAtIndex)(list->instance, index, element);
+}
+
+size_t
+parcList_Size(const PARCList *list)
+{
+ return (list->interface->Size)(list->instance);
+}
+
+PARCList *
+parcList_SubList(PARCList *list, size_t fromIndex, size_t toIndex)
+{
+ return (list->interface->SubList)(list->instance, fromIndex, toIndex);
+}
+
+void**
+parcList_ToArray(PARCList *list)
+{
+ return (list->interface->ToArray)(list->instance);
+}
diff --git a/libparc/parc/algol/parc_List.h b/libparc/parc/algol/parc_List.h
new file mode 100644
index 00000000..6c17453c
--- /dev/null
+++ b/libparc/parc/algol/parc_List.h
@@ -0,0 +1,768 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_List.h
+ * @ingroup datastructures
+ * @brief PARC (Generic) List
+ *
+ * An ordered collection (also known as a sequence).
+ * The user of this interface has precise control over where in the list each element is inserted.
+ * The user can access elements by their integer index (position in the list), and search for elements in the list.
+ * Unlike sets, lists typically allow duplicate elements.
+ * More formally, lists typically allow pairs of elements e1 and e2 such that e1.equals(e2), and they typically allow
+ * multiple null elements if they allow null elements at all.
+ * It is not inconceivable that someone might wish to implement a list that prohibits duplicates,
+ * by throwing runtime exceptions when the user attempts to insert them, but we expect this usage to be rare.
+ *
+ */
+#ifndef libparc_parc_List_h
+#define libparc_parc_List_h
+
+#include <stdbool.h>
+
+struct parc_list;
+/**
+ * @typedef PARCList
+ * @brief An ordered collection (also known as a sequence).
+ */
+typedef struct parc_list PARCList;
+
+#include <parc/algol/parc_HashCode.h>
+
+#include <parc/algol/parc_Collection.h>
+#include <parc/algol/parc_Object.h>
+
+/**
+ * @typedef PARCListInterface
+ * @brief The interface of a `PARCList` including functions such as copy, destroy, add, etc.
+ */
+typedef struct parc_list_interface {
+ /**
+ * Copy an instance of `PARCList`
+ *
+ * @param [in] original An instance of `PARCList` to copy
+ *
+ * @return A pointer to the new list.
+ */
+ void *(*Copy)(const PARCList * original);
+
+ /**
+ * Destroy the List
+ *
+ * @param [in,out] instancePtr
+ * @return a pointer to the destroyed List.
+ */
+ void (*Destroy)(void **instancePtr);
+
+ /**
+ * Tests if this list is empty.
+ *
+ * @param [in] instance
+ * @return true if the list is empty
+ */
+ bool (*IsEmpty)(const void *instance);
+
+ /**
+ * Appends the specified element to the end of this list (optional operation).
+ *
+ * @param [in,out] The instance of `PARCList` to append the element to
+ * @param [in] element The pointer to the element to be added to the `PARCList`
+ * @return true if the element was added successfully.
+ */
+ bool (*Add)(void *instance, PARCObject *element);
+
+ /**
+ * Inserts the specified element at the specified position in this list (optional operation).
+ *
+ * @param [in,out] instance The instance of `PARCList` to modify
+ * @param [in] index The index in `PARCList` at which to insert the @p element
+ * @param [in] element The element to insert in `PARCList` at @p index.
+ */
+ void (*AddAtIndex)(void *instance, int index, PARCObject *element);
+
+ /**
+ * Append elements of @p collection to @p instance
+ *
+ * Appends all of the elements in the specified collection to the end of this list,
+ * in the order that they are returned by the specified collection's iterator (optional operation).
+ *
+ * @param [in,out] instance The `PARCList` to be modified
+ * @param [in] collection The collection to be added
+ * @return true if add is successful.
+ */
+ bool (*AddCollection)(void *instance, PARCCollection *collection);
+
+ /**
+ * Inserts all of the elements in the specified collection into this list at the specified position (optional operation)
+ *
+ * @param [in,out] instance The `PARCList` to be modified
+ * @param [in] index The position at which to insert the @p collection
+ * @param [in] collection The collection to be added
+ * @return true if add is successful.
+ * @endcode
+ */
+ bool (*AddCollectionAtIndex)(void *instance, int index, PARCCollection *collection);
+
+ /**
+ * Removes all of the elements from this list (optional operation).
+ *
+ * @param [in,out] instance The instance of `PARCList` to empty.
+ */
+ void (*Clear)(void *instance);
+
+ /**
+ * Returns true if this list contains the specified element.
+ *
+ * @param [in] instance The instance of `PARCList` to inspect
+ * @param [in] element The element to search for in @p instance
+ * @return true if the @p element is found in @p instance.
+ */
+ bool (*Contains)(const void *instance, const PARCObject *element);
+
+ /**
+ * Returns true if this list contains all of the elements of the specified collection.
+ *
+ * @param [in] instance The instance of `PARCList` to inspect
+ * @param [in] collection The instance of {@link PARCCollection} whose elements are sought in @p instance
+ * @return true if all of the elements in @p collection is found in @p instance
+ */
+ bool (*ContainsCollection)(const void *instance, const PARCCollection *collection);
+
+ /**
+ * Compares the specified object with this list for equality.
+ *
+ * @param [in] xInstance The first `PARCList` instance to compare
+ * @param [in] yInstance The second `PARCList` instance to compare
+ * @return true if the two instances are equal
+ */
+ bool (*Equals)(const void *xInstance, const void *yInstance);
+
+ /**
+ * Returns the element at the specified position in this list.
+ *
+ * @param [in] instance A pointer to the instance of `PARCList`
+ * @param index The index of the element to be returned
+ * @return A pointer to the element at @p index
+ */
+ PARCObject *(*GetAtIndex)(const void *instance, size_t index);
+
+ /**
+ * Returns the hash code value for this list.
+ *
+ * @param [in] instance A pointer to the instance of `PARCList`
+ * @return int The hash code value
+ */
+ PARCHashCode (*HashCode)(const void *instance);
+
+ /**
+ * Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element.
+ *
+ * @param [in] instance A pointer to the instance of `PARCList`
+ * @param [in] element A pointer to the element to locate in @p instance
+ * @return size_t the index of the first located @p element or -1 if not found
+ */
+ size_t (*IndexOf)(const void *instance, const PARCObject *element);
+
+ /**
+ * Returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element.
+ *
+ * @param [in] instance A pointer to the instance of `PARCList`
+ * @param [in] element A pointer to the element to locate in @p instance
+ * @return size_t the index of the last located @p element or -1 if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ size_t (*LastIndexOf)(void *instance, const PARCObject *element);
+
+ /**
+ * Removes the element at the specified position in this list (optional operation).
+ *
+ * @param [in,out] instance A pointer to the instance of `PARCList` to modify
+ * @param [in] index The index of the element to remove
+ * @return A pointer to the removed element
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ PARCObject *(*RemoveAtIndex)(PARCList * list, size_t index);
+
+ /**
+ * Removes the first occurrence of the specified element from this list, if it is present (optional operation).
+ *
+ * @param [in,out] instance A pointer to the instance of `PARCList` to modify
+ * @param element The element to find and remove
+ * @return true if element found and removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ bool (*Remove)(void *instance, const PARCObject *element);
+
+ /**
+ * Removes from this list all of its elements that are contained in the specified collection (optional operation).
+ *
+ * @param [in,out] instance A pointer to the instance of `PARCList` to modify
+ * @param collection The instance of {@link PARCCollection} whose elements should be found in the @p instance and removed.
+ * @return true if the elements are found and removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ bool (*RemoveCollection)(void *instance, const PARCCollection *collection);
+
+ /**
+ * Retains only the elements in this list that are contained in the specified collection (optional operation).
+ *
+ * @param [in,out] instance A pointer to the instance of `PARCList` to modify
+ * @param collection The instance of {@link PARCCollection} whose elements should be retained in
+ * the @p instance while all other elements are removed.
+ * @return true if the operation is successful
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ bool (*RetainCollection)(void *instance, const PARCCollection *collection);
+
+ /**
+ * Replaces the element at the specified position in this list with the specified element (optional operation).
+ *
+ * @param [in,out] instance A pointer to the instance of `PARCList` to modify
+ * @param index The position in @p instance to replace with @p element
+ * @param element The element to put into @p instance at @p index, replacing the current value.
+ * @return
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ void *(*SetAtIndex)(void *instance, size_t index, PARCObject * element);
+
+ /**
+ * Returns the number of elements in this list.
+ *
+ * @param [in] instance A pointer to the instance of `PARCList` to inspect
+ * @return size_t Number of elements in the list
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ size_t (*Size)(const void *instance);
+
+ /**
+ * Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive.
+ *
+ * @param [in] instance A pointer to the instance of `PARCList` to inspect
+ * @param [in] fromIndex The starting index into the list
+ * @param [in] toIndex The end index into the list
+ * @return A pointer to the sub list
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ PARCList *(*SubList)(const void *instance, size_t fromIndex, size_t toIndex);
+
+ /**
+ * Returns an array containing all of the elements in this list in proper sequence (from first to last element).
+ *
+ * @param [in] instance A pointer to the instance of `PARCList` to inspect
+ * @return A pointer to a pointer to the array containing the elements of the list in proper sequence.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ void** (*ToArray)(const void *instance);
+} PARCListInterface;
+
+/**
+ * Increase the number of references to a `PARCList`.
+ *
+ * Note that new `PARCList` is not created,
+ * only that the given `PARCList` reference count is incremented.
+ * Discard the reference by invoking `parcList_Release`.
+ *
+ * @param list A pointer to the original `PARCList`.
+ * @return The value of the input parameter @p list.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList);
+ *
+ * PARCList *list2 = parcList_Acquire(list);
+ *
+ * parcList_Release(&list);
+ * parcList_Release(&list2);
+ * }
+ * @endcode
+ *
+ * @see parcList_Release
+ */
+PARCList *parcList_Acquire(const PARCList *list);
+
+/**
+ * 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 interface will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] listPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList);
+ *
+ * parcList_Release(&list);
+ * }
+ * @endcode
+ */
+void parcList_Release(PARCList **listPtr);
+
+/**
+ * Create an independent copy the given `PARCList`
+ *
+ * A new list is created as a complete copy of the original.
+ *
+ * @param [in] list A valid pointer to a `PARCList` instance (cannot be NULL)
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCList` instance.
+ *
+ * @throws trapIllegalValue if @p instance is NULL.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList);
+ *
+ * PARCList *copy = parcList_Copy(list);
+ *
+ * parcList_Release(&copy);
+ * parcList_Release(&list);
+ * }
+ * @endcode
+ *
+ */
+PARCList *parcList_Copy(const PARCList *list);
+
+/**
+ * Tests if this list is empty.
+ *
+ * Return true if the list is empty, false otherwise
+ *
+ * @param list A pointer to the instance of `PARCList` to test
+ * @return True if the list is empty, else False
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_IsEmpty(const PARCList *list);
+
+/**
+ * Appends the specified element to the end of this list (optional operation).
+ *
+ * @param [in,out] list A pointer to the instance of `PARCList` to modify
+ * @param [in] element The element to add to the end of the `PARCList`
+ * @return True if the add is successful
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_Add(PARCList *list, void *element);
+
+/**
+ * Add all of the pointers in the given array of pointers to the `PARCList`.
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified.
+ * @param [in] argc The number of values in @p argv.
+ * @param [in] argv An array void * values.
+ *
+ * @return True if the add is successful
+ *
+ * Example:
+ * @code
+ * {
+ * PARCList *list = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList);
+ *
+ * int elements[] = { 1, 2, 3 };
+ *
+ * parcList_AddAll(array, 3, elements);
+ * size_t actual = parcList_Length(array);
+ *
+ * assertTrue(3 == actual, "Expected=%d, actual=%d", 3, actual);
+ *
+ * parcListRelease(&array);
+ * }
+ * @endcode
+ */
+bool parcList_AddAll(PARCList *list, size_t argc, void **argv);
+
+/**
+ * Inserts the specified element at the specified position in this list (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified
+ * @param [in] index The specified position in the list
+ * @param [in] element The element to be added to the specified position.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcList_AddAtIndex(PARCList *list, int index, void *element);
+
+/**
+ * Appends all of the elements in the specified collection to the end of this list,
+ * in the order that they are returned by the specified collection's iterator (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified
+ * @param [in] collection A pointer to an istance of {@link PARCCollection} to be added to the list
+ * @return True if add is successful
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_AddCollection(PARCList *list, PARCCollection *collection);
+
+/**
+ * Inserts all of the elements in the specified collection into this list at the specified position (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified
+ * @param [in] index The position at which to insert the collection
+ * @param [in] collection A pointer to an istance of {@link PARCCollection} to be inserted into the list
+ * @return True if insertion is successful
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_AddCollectionAtIndex(PARCList *list, int index, PARCCollection *collection);
+
+/**
+ * Removes all of the elements from this list (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be cleared
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcList_Clear(PARCList *list);
+
+/**
+ * Returns true if this list contains the specified element.
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be checked
+ * @param [in] element The element to be added to the specified position.
+ * @return True if the element is contained in the list
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_Contains(const PARCList *list, void *element);
+
+/**
+ * Returns true if this list contains all of the elements of the specified collection.
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be checked
+ * @param [in] collection A pointer to the instance of {@link PARCCollection} to be checked.
+ * @return True if all of the elements in the collection are found in the list.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_ContainsCollection(PARCList *list, PARCCollection *collection);
+
+
+/**
+ * Determine if two `PARCList` instances are equal.
+ *
+ * Two `PARCList` instances are equal if, and only if,
+ * the size of the lists are equal and each element in the list is equal and
+ * in the same order.
+ *
+ * The following equivalence relations on non-null `PARCList` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCList_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcList_Equals(x, y)` must return true if and only if
+ * `parcList_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcList_Equals(x, y)` returns true and
+ * `parcList_Equals(y, z)` returns true,
+ * then `parcList_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcList_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcList_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] x A pointer to a `PARCList` instance.
+ * @param [in] y A pointer to a `PARCList` instance.
+ * @return true if the two `PARCList` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCList *a = parcList_Create();
+ * PARCList *b = parcList_Create();
+ *
+ * if (parcList_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool parcList_Equals(const PARCList *x, const PARCList *y);
+
+/**
+ * Returns the element at the specified position in this list.
+ * If the index is out of bounds, it will trap with an out-of-bounds.
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be checked
+ * @param [in] index The index of the element to be returned
+ * @return A pointer to the element.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcList_GetAtIndex(const PARCList *list, size_t index);
+
+/**
+ * Returns the hash code value for this list.
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be hashed
+ * @return The hash code value
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int parcList_HashCode(const PARCList *list);
+
+/**
+ * Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element.
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be hashed.
+ * @param [in] element A pointer to an element to check for list inclusion.
+ * @return The index of the first occurance of @p element, or -1 if it is not present
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t parcList_IndexOf(const PARCList *list, PARCObject *element);
+
+/**
+ * Returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element.
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be hashed.
+ * @param [in] element A pointer to an element to check for list inclusion.
+ * @return The index of the last occurance of @p element, or -1 if it is not present
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ssize_t parcList_LastIndexOf(const PARCList *list, PARCObject *element);
+
+/**
+ * Removes the element at the specified position in this list (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified.
+ * @param [in] index The index of the element to be removed
+ * @return non NULL A pointer to the element removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcList_RemoveAtIndex(PARCList *list, size_t index);
+
+/**
+ * Removes the first occurrence of the specified element from this list, if it is present (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified.
+ * @param [in] element A pointer to the element to be removed from the `PARCList`
+ * @return true The element was found and removed, false if it was not found.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_Remove(PARCList *list, PARCObject *element);
+
+/**
+ * Removes from this list all of its elements that are contained in the specified collection (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified.
+ * @param [in] collection A pointer to the instance of {@link PARCCollection} to be removed from the `PARCList`
+ * @return true The collection was found and removed, false if it was not found.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_RemoveCollection(PARCList *list, PARCCollection *collection);
+
+/**
+ * Retains only the elements in this list that are contained in the specified collection (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified.
+ * @param [in] collection A pointer to the instance of {@link PARCCollection} to be found and retained in the `PARCList`
+ * @return true if the function was successful
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcList_RetainCollection(PARCList *list, PARCCollection *collection);
+
+/**
+ * Replaces the element at the specified position in this list with the specified element (optional operation).
+ *
+ * @param [in,out] list A pointer to the `PARCList` instance to be modified.
+ * @param [in] index The position at which the element should be replaced with @p element
+ * @param [in] element A pointer to the element to be inserted at the specified position
+ * @return A pointer to the element previously at that position.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCObject *parcList_SetAtIndex(PARCList *list, size_t index, PARCObject *element);
+
+/**
+ * Returns the number of elements in this list.
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be measured.
+ * @return The size of the @p list
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcList_Size(const PARCList *list);
+
+/**
+ * Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive.
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be measured.
+ * @param [in] fromIndex The position to start the view (inclusive)
+ * @param [in] toIndex The position to end the view (exclusive)
+ * @return a pointer to an instance of `PARCList` containing the subList requested
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCList *parcList_SubList(PARCList *list, size_t fromIndex, size_t toIndex);
+
+/**
+ * Returns an array containing all of the elements in this list in proper sequence (from first to last element).
+ *
+ * @param [in] list A pointer to the `PARCList` instance to be sorted.
+ * @return A pointer to a pointer to an Array containing the sorted elements
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void**parcList_ToArray(PARCList *list);
+
+/**
+ * Create an instance of `PARCList` that uses the @p interface to provide functions and the @p instance to provide
+ * initial elements of the list.
+ * @param [in] instance An initial set of elements for the new instance of `PARCList`
+ * @param [in] interface A pointer to an instance of {@link PARCListInterface} containing a set of list functions
+ * @return A pointer to a new instance of `PARCList`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCList *parcList(void *instance, PARCListInterface *interface);
+
+/**
+ * Create an instance of `PARCList` that uses the @p interface to provide functions and the @p instance to provide
+ * initial elements of the list.
+ * @param [in] instance An initial set of elements for the new instance of `PARCList`
+ * @param [in] interface A pointer to an instance of {@link PARCListInterface} containing a set of list functions
+ * @return A pointer to a new instance of `PARCList`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCList *parcList_Create(void *instance, PARCListInterface *interface);
+
+#endif // libparc_parc_List_h
diff --git a/libparc/parc/algol/parc_Map.c b/libparc/parc/algol/parc_Map.c
new file mode 100755
index 00000000..e5371c99
--- /dev/null
+++ b/libparc/parc/algol/parc_Map.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <parc/algol/parc_Map.h>
diff --git a/libparc/parc/algol/parc_Map.h b/libparc/parc/algol/parc_Map.h
new file mode 100755
index 00000000..c63b23c5
--- /dev/null
+++ b/libparc/parc/algol/parc_Map.h
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Map.h
+ * @ingroup datastructures
+ * @brief An object that maps keys to values.
+ *
+ * A map cannot contain duplicate keys; each key can map to at most one value.
+ *
+ */
+#ifndef libparc_parc_Map_h
+#define libparc_parc_Map_h
+#include <stdbool.h>
+
+struct parc_map;
+typedef struct parc_map PARCMap;
+
+typedef struct parc_map_interface {
+ /**
+ * Removes all of the mappings from this map.
+ *
+ * The map will be empty after this call returns.
+ *
+ * @param [in,out] map The instance of `PARCMap` to be cleared of mappings
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+ void (*parcMap_Clear)(PARCMap *map);
+
+ /**
+ * Returns true if this map contains a mapping for the specified key.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to check
+ * @param [in] key A pointer to the key to check for in @p map
+ *
+ * @return True if the map cnatins a mapping for the specified key
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+ bool (*parcMap_ContainsKey)(PARCMap *map, void *key);
+
+ /**
+ * Returns true if this map maps one or more keys to the specified value.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to check
+ * @param [in] value A pointer to the value to check for in @p map
+ *
+ * @return True if the map contains one or more keys that map to @p value.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+ bool (*parcMap_ContainsValue)(PARCMap *map, void *value);
+
+ /**
+ * Compares the specified object with this map for equality.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to check
+ * @param [in] other A pointer to the other instance of `PARCMap` to compare
+ * @return True is the two maps are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+ bool (*parcMap_Equals)(PARCMap *map, void *other);
+
+ /**
+ * Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to check
+ * @param [in] key A pointer to the key to check for in @p map
+ *
+ * @return NULL If the @p key is not present in @p map
+ * @return NOT NULL The value to which the @p key is mapped.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+ void *(*parcMap_Get)(PARCMap * map, void *key);
+
+ /**
+ * Returns the hash code value for this map.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to hash
+ *
+ * @return The hash of the instance of `PARCMap`
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+ int (*parcMap_HashCode)(PARCMap *map);
+
+ /**
+ * Returns true if this map contains no key-value mappings.
+ *
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to check
+ *
+ * @return True if the map contains no mappings.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+ bool (*parcMap_IsEmpty)(PARCMap *map);
+
+ /**
+ * Associates the specified value with the specified key in this map (optional operation).
+ *
+ * @param [in,out] map A pointer to the instance of `PARCMap` in which to insert @p value at @p key.
+ * @param [in] key A pointer to the key in @p map in which to insert @p value.
+ * @param [in] value A pointer to the the value to insert at @p key in @p map.
+ *
+ * @return
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+ void *(*parcMap_Put)(PARCMap * map, void *key, void *value);
+
+ /**
+ * Copies all of the mappings from the specified map to this map (optional operation).
+ *
+ * @param [in,out] map The instance of `PARCMap` to be modified.
+ * @param [in] other The instance of `PARCMap` whose mappings should be copied to @p map.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+ void (*parcMap_PutAll)(PARCMap *map, PARCMap *other);
+
+ /**
+ * Removes the mapping for a key from this map if it is present (optional operation).
+ *
+ * @param [in,out] map The instance of `PARCMap` to be modified.
+ * @param [in] key The key to the mapping to be removed
+ *
+ * @return
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+ void *(*parcMap_Remove)(PARCMap * map, void *key);
+
+ /**
+ * Returns the number of key-value mappings in this map.
+ *
+ * @param [in,out] map The instance of `PARCMap` to be inspected.
+ *
+ * @return int The number of mappings in the map
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+ int (*parcMap_Size)(PARCMap *map);
+} PARCMapInterface;
+
+/**
+ * Create a PARCMap instance.
+ *
+ * Create an instance of `PARCMap` wrapping the given pointer to a base map
+ * interface and the {@ link PARCMapInterface} structure containing pointers
+ * to functions performing the actual Map operations.
+ *
+ * @param [in] map A pointer to the structure for the new instance of `PARCMap`
+ * @param [in] interface A pointer to the instance of `PARCMapInterface`
+ * @return A new instance of `PARCMap`
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCMap *parcMap_Create(void *map, PARCMapInterface *interface);
+
+/**
+ * Removes all of the mappings from this map.
+ *
+ * The map will be empty after this call returns.
+ *
+ * @param [in,out] map A pointer to the instance of `PARCMap` to be cleared.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcMap_Clear(PARCMap *map);
+
+/**
+ * Returns true if this map contains a mapping for the specified key.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to be checked.
+ * @param [in] key A pointer to the key to be checked for in @p map
+ *
+ * @return True if the specified key is found in the map.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcMap_ContainsKey(PARCMap *map, void *key);
+
+/**
+ * Returns true if this map maps one or more keys to the specified value.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to be checked.
+ * @param [in] value A pointer to the value to be checked for in @p map
+ *
+ * @return True if the specified value has one or more keys pointing to it.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcMap_ContainsValue(PARCMap *map, void *value);
+
+/**
+ * Determine if two `PARCMap` instances are equal.
+ *
+ * Two `PARCMap` instances are equal if, and only if, the maps have the same
+ * number of elements, all of the keys are equal and the values to which they point are equal
+ *
+ * The following equivalence relations on non-null `PARCMap` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCMap_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcMap_Equals(x, y)` must return true if and only if
+ * `parcMap_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcMap_Equals(x, y)` returns true and
+ * `parcMap_Equals(y, z)` returns true,
+ * then `parcMap_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcMap_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcMap_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] map A pointer to a `PARCMap` instance.
+ * @param [in] other A pointer to a `PARCMap` instance.
+ * @return true if the two `PARCMap` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCMap *a = parcMap_Create();
+ * PARCMap *b = parcMap_Create();
+ *
+ * if (parcMap_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool parcMap_Equals(PARCMap *map, void *other);
+
+/**
+ * Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to be checked.
+ * @param [in] key A pointer to the key to be checked for which the value is to be returned.
+ *
+ * @return Null if no mapping for @p key exists
+ * @return Non Null A pointer to the value for @p key
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void *parcMap_Get(PARCMap *map, void *key);
+
+/**
+ * Returns the hash code value for this map.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to be hashed.
+ *
+ * @return The hash value for the @p map
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+int parcMap_HashCode(PARCMap *map);
+
+/**
+ * Returns true if this map contains no key-value mappings.
+ *
+ * @param [in] map A pointer to the instance of `PARCMap` to be checked.
+ *
+ * @return True if the @p map is empty. else false.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcMap_IsEmpty(PARCMap *map);
+
+/**
+ * Associates the specified value with the specified key in this map (optional operation).
+ *
+ * @param [in,out] map A pointer to the instance of `PARCMap` into which the key,value pair should be inserted.
+ * @param [in] key A pointer to the key to be inserted in @p map
+ * @param [in] value A pointer to the value to be inserted in @p map at @p key
+ *
+ * @return The previous value at @p key if one exists, else NULL
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void *parcMap_Put(PARCMap *map, void *key, void *value);
+
+/**
+ * Copies all of the mappings from the specified map to this map (optional operation).
+ *
+ * @param [in,out] map The map into which all the mappings from @p other should be copied.
+ * @param [in] other The instance of `PARCMap` whose mappings should be copied into @p map
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcMap_PutAll(PARCMap *map, PARCMap *other);
+
+/**
+ * Removes the mapping for a key from this map if it is present (optional operation).
+ *
+ *
+ * @param [in,out] map The instance of `PARCMap` in which @p key should be removed if present.
+ * @param [in] key The pointer to the key representing the mapping that should be removed from @p map.
+ *
+ * @return A pointer to the value previously mapped to @p key, if @p key exists.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void *parcMap_Remove(PARCMap *map, void *key);
+
+/**
+ * Returns the number of key-value mappings in this map.
+ *
+ * @param [in,out] map The instance of `PARCMap` to be measured
+ *
+ * @return The number of mappings in @p map.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+int parcMap_Size(PARCMap *map);
+#endif // libparc_parc_Map_h
diff --git a/libparc/parc/algol/parc_Memory.c b/libparc/parc/algol/parc_Memory.c
new file mode 100755
index 00000000..e444baba
--- /dev/null
+++ b/libparc/parc/algol/parc_Memory.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 <LongBow/runtime.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_StdlibMemory.h>
+
+static const PARCMemoryInterface *parcMemory = &PARCStdlibMemoryAsPARCMemory;
+
+const PARCMemoryInterface *
+parcMemory_SetInterface(const PARCMemoryInterface *memoryProvider)
+{
+ assertFalse(memoryProvider == &PARCMemoryAsPARCMemory,
+ "You cannot use PARCMemoryAsPARCMemory as a memory provider for parcMemory.");
+ const PARCMemoryInterface *result = parcMemory;
+ parcMemory = memoryProvider;
+
+ return result;
+}
+
+size_t
+parcMemory_RoundUpToCacheLine(const size_t size)
+{
+ return parcMemory_RoundUpToMultiple(size, LEVEL1_DCACHE_LINESIZE);
+}
+
+size_t
+parcMemory_RoundUpToMultiple(const size_t size, const size_t multiple)
+{
+ if (size == 0) {
+ return multiple;
+ }
+
+ if (multiple == 0) {
+ return size;
+ }
+
+ size_t remainder = size % multiple;
+ if (remainder == 0) {
+ return size;
+ }
+ return size + multiple - remainder;
+}
+
+void *
+parcMemory_Allocate(const size_t size)
+{
+ return ((PARCMemoryAllocate *) parcMemory->Allocate)(size);
+}
+
+void *
+parcMemory_AllocateAndClear(const size_t size)
+{
+ return ((PARCMemoryAllocateAndClear *) parcMemory->AllocateAndClear)(size);
+}
+
+int
+parcMemory_MemAlign(void **pointer, const size_t alignment, const size_t size)
+{
+ return ((PARCMemoryMemAlign *) parcMemory->MemAlign)(pointer, alignment, size);
+}
+
+void
+parcMemory_DeallocateImpl(void **pointer)
+{
+ ((PARCMemoryDeallocate *) parcMemory->Deallocate)(pointer);
+}
+
+void *
+parcMemory_Reallocate(void *pointer, size_t newSize)
+{
+ return ((PARCMemoryReallocate *) parcMemory->Reallocate)(pointer, newSize);
+}
+
+char *
+parcMemory_StringDuplicate(const char *string, const size_t length)
+{
+ return ((PARCMemoryStringDuplicate *) parcMemory->StringDuplicate)(string, length);
+}
+
+uint32_t
+parcMemory_Outstanding(void)
+{
+ return ((PARCMemoryOutstanding *) parcMemory->Outstanding)();
+}
+
+char *
+parcMemory_Format(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+
+ va_list copy;
+ va_copy(copy, ap);
+ int length = vsnprintf(NULL, 0, format, copy);
+ va_end(copy);
+
+ char *result = NULL;
+ if (length >= 0) {
+ result = parcMemory_Allocate(length + 1);
+
+ if (result != NULL) {
+ vsprintf(result, format, ap);
+ }
+ }
+ return result;
+}
+
+PARCMemoryInterface PARCMemoryAsPARCMemory = {
+ .Allocate = (uintptr_t) parcMemory_Allocate,
+ .AllocateAndClear = (uintptr_t) parcMemory_AllocateAndClear,
+ .MemAlign = (uintptr_t) parcMemory_MemAlign,
+ .Deallocate = (uintptr_t) parcMemory_DeallocateImpl,
+ .Reallocate = (uintptr_t) parcMemory_Reallocate,
+ .StringDuplicate = (uintptr_t) parcMemory_StringDuplicate,
+ .Outstanding = (uintptr_t) parcMemory_Outstanding
+};
diff --git a/libparc/parc/algol/parc_Memory.h b/libparc/parc/algol/parc_Memory.h
new file mode 100644
index 00000000..fe3c4b5a
--- /dev/null
+++ b/libparc/parc/algol/parc_Memory.h
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Memory.h
+ * @ingroup memory
+ * @brief A Facade to memory allocation features.
+ *
+ * PARC Memory provides an interface implementing many regularly available memory allocation functions.
+ * This interface is a Facade that software implementors may use to substitute different kinds of underlying
+ * Interfaces of these allocation fucntions.
+ * Notable examples are PARC Safe Memory and PARC Stdlib Memory.
+ *
+ */
+#ifndef libparc_parc_Memory_h
+#define libparc_parc_Memory_h
+
+#include <stdlib.h>
+#include <stdint.h>
+
+/**
+ * @typedef PARCMemoryAllocate
+ * @brief Function signature for memory allocator.
+ *
+ */
+typedef void *(PARCMemoryAllocate)(size_t size);
+
+typedef void *(PARCMemoryAllocateAndClear)(size_t size);
+
+typedef int (PARCMemoryMemAlign)(void **pointer, size_t alignment, size_t size);
+
+typedef void (PARCMemoryDeallocate)(void **pointer);
+
+typedef void *(PARCMemoryReallocate)(void *pointer, size_t newSize);
+
+typedef char *(PARCMemoryStringDuplicate)(const char *string, size_t length);
+
+typedef uint32_t (PARCMemoryOutstanding)(void);
+
+/**
+ * @typedef PARCMemoryInterface
+ * @brief A structure containing pointers to functions that implement a PARC Memory manager.
+ *
+ * A 'PARC Memory' manager is a collection of inter-dependant functions that perform memory allocation,
+ * re-allocation, deallocation, and housekeeping.
+ *
+ * PARC Memory managers are cascadable, where one Interface may call other Interface in a chain.
+ * This permits the design and Interface of PARC Memory managers that specialise in fixed length memory sizes,
+ * reference counting, debugging and so forth.
+ */
+typedef struct parc_memory_interface {
+ /**
+ * A pointer to a function that allocates @p size bytes of memory
+ * and returns the allocation in the return value.
+ *
+ * @param [in] size The number of bytes to allocate.
+ *
+ * @return A `void *` pointer indicating the address of the allocated memory.
+ * @return NULL Memory allocation error.
+ *
+ * @see AllocateAndClear
+ * @see Reallocate
+ */
+ uintptr_t Allocate;
+
+ /**
+ * Performs the same operation as `Allocate` and then sets each byte of the allocated memory to zero.
+ *
+ * @param [in] size The number of bytes to allocate.
+ *
+ * @return A `void *` pointer indicating the address of the allocated memory.
+ * @return NULL Memory allocation error.
+ *
+ * @see Allocate
+ * @see Reallocate
+ */
+ uintptr_t AllocateAndClear;
+
+ /**
+ * A pointer to a function that allocates @p size bytes of memory such that the allocation's
+ * base address is an exact multiple of alignment,
+ * and returns the allocation in the value pointed to by @p pointer.
+ *
+ * The requested alignment must be a power of 2 greater than or equal to `sizeof(void *)`.
+ *
+ * Memory that is allocated can be used as an argument in subsequent call `Reallocate`, however
+ * `Reallocate` is not guaranteed to preserve the original alignment.
+ *
+ * @param [out] pointer A pointer to a `void *` pointer that will be set to the address of the allocated memory.
+ * @param [in] alignment A power of 2 greater than or equal to `sizeof(void *)`
+ * @param [in] size The number of bytes to allocate.
+ *
+ * @return 0 Successful
+ * @return EINVAL The alignment parameter is not a power of 2 at least as large as sizeof(void *)
+ * @return ENOMEM Memory allocation error.
+ *
+ * @see posix_memalign
+ */
+ uintptr_t MemAlign;
+
+ /**
+ * Deallocate memory previously allocated via `Allocate` or `AllocateAndClear`.
+ *
+ * @param [in,out] pointer A pointer to a `void *` pointer to the address of the allocated memory that will be set to zero.
+ *
+ * @see AllocateAndClear
+ * @see Allocate
+ * @see Reallocate
+ */
+ uintptr_t Deallocate;
+
+ /**
+ * Try to change the size of the allocation pointed to by @p pointer to @p newSize, and returns ptr.
+ * If there is not enough room to enlarge the memory allocation pointed to by @p pointer,
+ * create a new allocation,
+ * copy as much of the old data pointed to by @p pointer as will fit to the new allocation,
+ * deallocate the old allocation,
+ * and return a pointer to the allocated memory.
+ *
+ * If @p pointer is `NULL`,
+ * simply invoke the `Allocate` function to allocate memory aligned to the value of `sizeof(void *)` of @p newSize bytes.
+ * If @p newSize is zero and @p pointer is not NULL,
+ * a new, minimum sized object is allocated and the original object is freed.
+ *
+ * When extending a region previously allocated with `AllocateAndClear`,
+ * the additional memory is not guaranteed to be zero-filled.
+ *
+ * @param [in] pointer A pointer to previously allocated memory, or NULL.
+ * @param [in] newSize The size of the allocated memory.
+ *
+ * @return non-NULL A pointer to allocated memory.
+ * @return NULL A an error occurred.
+ *
+ * @see Deallocate
+ * @see AllocateAndClear
+ * @see Allocate
+ */
+ uintptr_t Reallocate;
+
+ /**
+ * Allocate sufficient memory for a copy of the string @p string,
+ * copy at most n characters from the string @p string into the allocated memory,
+ * and return the pointer to allocated memory.
+ *
+ * The copied string is always null-terminated.
+ *
+ * @param [in] string A pointer to a null-terminated string.
+ * @param [length] The maximum allows length of the resulting copy.
+ *
+ * @return non-NULL A pointer to allocated memory.
+ * @return NULL A an error occurred.
+ */
+ uintptr_t StringDuplicate;
+
+ /**
+ * Return the number of allocations outstanding. That is, the numbe of allocations
+ * that have been made, but not yet freed.
+ *
+ * @return The number of outstanding allocations known to this `PARCMemoryInterface`.
+ */
+ uintptr_t Outstanding;
+} PARCMemoryInterface;
+
+/**
+ *
+ */
+extern PARCMemoryInterface PARCMemoryAsPARCMemory;
+
+/**
+ * Set the current memory allocation interface.
+ *
+ * The previous interface is returned.
+ *
+ * @param [in] memoryProvider A pointer to a {@link PARCMemoryInterface} instance.
+ *
+ * @return A pointer to the previous `PARCMemoryInterface` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCMemoryInterface *previousInterface = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ * }
+ * @endcode
+ *
+ * @see PARCSafeMemoryAsPARCMemory
+ * @see PARCMemoryAsPARCMemory
+ * @see PARCStdlibMemoryAsPARCMemory
+ */
+const PARCMemoryInterface *parcMemory_SetInterface(const PARCMemoryInterface *memoryProvider);
+
+/**
+ * Allocate memory.
+ *
+ * Allocates @p size bytes of memory and returns the allocation in the return value.
+ *
+ * Memory that is allocated can be used as an argument in subsequent call `Reallocate`.
+ *
+ * @param [in] size The number of bytes to allocate.
+ *
+ * @return A `void *` pointer set to the address of the allocated memory.
+ * @return NULL Memory allocation error.
+ *
+ * Example:
+ * @code
+ * {
+ * void *allocatedMemory;
+ *
+ * allocateMemory = parcMemory_Allocate(100);
+ * if (allocatedMemory == NULL) {
+ * // allocation failed.
+ * }
+ * }
+ * @endcode
+ */
+void *parcMemory_Allocate(const size_t size);
+
+/**
+ * Performs the same operation as `Allocate` and then sets each byte of the allocated memory to zero.
+ *
+ * @param [in] size The number of bytes to allocate.
+ *
+ * @return A `void *` pointer set to the address of the allocated memory.
+ * @return NULL Memory allocation error.
+ *
+ * Example:
+ * @code
+ * {
+ * void *allocatedMemory;
+ *
+ * allocatedMemory = parcMemory_AllocateAndClear(100);
+ * if (allocatedMemory == NULL)
+ * // allocation failed
+ * }
+ * }
+ * @endcode
+ *
+ * @see parcMemory_Allocate
+ */
+void *parcMemory_AllocateAndClear(const size_t size);
+
+/**
+ * Allocate aligned memory.
+ *
+ * Allocates @p size bytes of memory such that the allocation's
+ * base address is an exact multiple of alignment,
+ * and returns the allocation in the value pointed to by @p pointer.
+ *
+ * The requested alignment must be a power of 2 greater than or equal to `sizeof(void *)`.
+ *
+ * Memory that is allocated can be used as an argument in subsequent call `Reallocate`, however
+ * `Reallocate` is not guaranteed to preserve the original alignment.
+ *
+ * @param [out] pointer A pointer to a `void *` pointer that will be set to the address of the allocated memory.
+ * @param [in] alignment A power of 2 greater than or equal to `sizeof(void *)`
+ * @param [in] size The number of bytes to allocate.
+ *
+ * @return 0 Successful
+ * @return EINVAL The alignment parameter is not a power of 2 at least as large as sizeof(void *)
+ * @return ENOMEM Memory allocation error.
+ *
+ * Example:
+ * @code
+ * {
+ * void *allocatedMemory;
+ *
+ * int failure = parcMemory_MemAlign(&allocatedMemory, sizeof(void *), 100);
+ * if (failure == 0) {
+ * parcMemory_Deallocate(&allocatedMemory);
+ * // allocatedMemory is now equal to zero.
+ * }
+ * }
+ * @endcode
+ * @see `posix_memalign`
+ */
+int parcMemory_MemAlign(void **pointer, const size_t alignment, const size_t size);
+
+/**
+ * Deallocate memory previously allocated via `Allocate` or `AllocateAndClear`.
+ *
+ * @param [in,out] pointer A pointer to a `void *` pointer to the address of the allocated memory that will be set to zero.
+ *
+ * Example:
+ * @code
+ * {
+ * void *allocatedMemory;
+ *
+ * allocatedMemory = parcMemory_Allocate(100);
+ * if (allocatedMemory == NULL) {
+ * // allocation failed
+ * }
+ * }
+ * @endcode
+ *
+ * @see parcMemory_Allocate
+ * @see parcMemory_AllocateAndClear
+ */
+void parcMemory_DeallocateImpl(void **pointer);
+
+#define parcMemory_Deallocate(_pointer_) parcMemory_DeallocateImpl((void **) _pointer_)
+
+/**
+ * Try to change the size of the allocation pointed to by @p pointer to @p newSize, and returns ptr.
+ * If there is not enough room to enlarge the memory allocation pointed to by @p pointer,
+ * create a new allocation,
+ * copy as much of the old data pointed to by @p pointer as will fit to the new allocation,
+ * deallocate the old allocation,
+ * and return a pointer to the allocated memory.
+ *
+ * If @p pointer is `NULL`,
+ * simply invoke the {@link parcMemory_Allocate} function to allocate memory aligned to the value of `sizeof(void *)` of @p newSize bytes.
+ * If @p newSize is zero and @p pointer is not NULL,
+ * a new, minimum sized object is allocated and the original object is freed.
+ *
+ * When extending a region previously allocated with `AllocateAndClear`,
+ * the additional memory is not guaranteed to be zero-filled.
+ *
+ * @param [in] pointer A pointer to previously allocated memory, or NULL.
+ * @param [in] newSize The size of the allocated memory.
+ *
+ * @return non-NULL A pointer to allocated memory.
+ * @return NULL A an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * void *allocatedMemory;
+ *
+ * allocateMemory = parcMemory_Allocate(100);
+ *
+ * allocatedMemory = parcMemory_Reallocate(allocatedMemory, sizeof(void *), 200);
+ *
+ * parcMemory_Deallocate(&allocatedMemory);
+ * }
+ * @endcode
+ *
+ * @see parcMemory_Deallocate
+ * @see parcMemory_Allocate
+ */
+void *parcMemory_Reallocate(void *pointer, size_t newSize);
+
+/**
+ * Allocate sufficient memory for a copy of the string @p string,
+ * copy at most n characters from the string @p string into the allocated memory,
+ * and return the pointer to allocated memory.
+ *
+ * The copied string is always null-terminated.
+ *
+ * @param [in] string A pointer to a null-terminated string.
+ * @param [in] length The maximum allowed length of the resulting copy.
+ *
+ * @return non-NULL A pointer to allocated memory.
+ * @return NULL A an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * char *string = "this is a string";
+ * char *copy = parcMemory_StringDuplicate(string, strlen(string));
+ *
+ * if (copy != NULL) {
+ * . . .
+ * parcMemory_Deallocate(&copy);
+ * }
+ * }
+ * @endcode
+ *
+ * @see {@link parcMemory_Deallocate()}
+ */
+char *parcMemory_StringDuplicate(const char *string, const size_t length);
+
+/**
+ * Return the number of outstanding allocations managed by this allocator.
+ *
+ * When you allocate memory, this count goes up by one. When you deallocate, it goes down by one.
+ * A well-behaved program will terminate with a call to parcMemory_Outstanding() returning 0.
+ *
+ * @return The number of memory allocations still outstanding (remaining to be deallocated).
+ *
+ * Example:
+ * @code
+ * {
+ * uint32_t numberOfAllocations = parcMemory_Outstanding();
+ * }
+ * @endcode
+ */
+uint32_t parcMemory_Outstanding(void);
+
+/**
+ * Round up a given number of bytes to be a multiple of the cache line size on the target computer.
+ *
+ * @param [in] size The number of bytes to round up.
+ *
+ * @return The number of bytes that are a multiple of the cache line size on the target computer.
+ *
+ * Example:
+ * @code
+ * {
+ * size_t size = parcMemory_RoundUpToCacheLine(14);
+ * }
+ * @endcode
+ *
+ * @see parcMemory_RoundUpToMultiple
+ */
+size_t parcMemory_RoundUpToCacheLine(const size_t size);
+
+/**
+ * Round up a given number of bytes to be an even multiple.
+ *
+ * @param [in] size The number of bytes to round up.
+ * @param [in] multiple The number of bytes to round up.
+ *
+ * @return The number of bytes that are an even multiple of @p multiple.
+ *
+ * Example:
+ * @code
+ * {
+ * size_t size = parcMemory_RoundUp(14, 20);
+ * }
+ * @endcode
+ *
+ * @see parcMemory_RoundUpToCacheLine
+ */
+size_t parcMemory_RoundUpToMultiple(size_t size, size_t multiple);
+
+/**
+ * @def parcMemory_SafeFree
+ *
+ * Free only non-null pointers to memory
+ *
+ * @param memory A pointer to allocated memory
+ *
+ */
+#define parcMemory_SafeFree(memory) do { if (memory != NULL) { parcMemory_Deallocate(& (memory)); } } while (0)
+
+/**
+ * Allocate a printf(3) style formatted string.
+ * The result must be deallocated via `parcMemory_Deallocate`
+ *
+ * This function is equivalent to the `asprintf(3)` function in the standard library.
+ *
+ * @param [in] format A pointer to nul-terminated C string containing a printf style format specification.
+ *
+ * @return non-NULL A pointer to allocated memory containing the formatted string.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * char *string = parcMemory_Format("Hello %s", "World");
+ *
+ * parcMemory_Deallocated(&string);
+ * }
+ * @endcode
+ */
+char *parcMemory_Format(const char *format, ...);
+#endif // libparc_parc_Memory_h
diff --git a/libparc/parc/algol/parc_Network.c b/libparc/parc/algol/parc_Network.c
new file mode 100644
index 00000000..35279648
--- /dev/null
+++ b/libparc/parc/algol/parc_Network.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/socket.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <netdb.h>
+
+#include <parc/algol/parc_Network.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_URI.h>
+
+struct sockaddr *
+parcNetwork_SockAddress(const char *address, in_port_t port)
+{
+ // this is the final return value from the function
+ struct sockaddr *addr = NULL;
+
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = AI_ADDRCONFIG;
+
+ // getaddrinfo allocates this pointer
+ struct addrinfo *ai;
+ int failure = getaddrinfo(address, NULL, &hints, &ai);
+ if (failure == 0) {
+ switch (ai->ai_family) {
+ case PF_INET: {
+ struct sockaddr_in *result = parcMemory_AllocateAndClear(sizeof(struct sockaddr_in));
+ assertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(struct sockaddr_in));
+ if (result != NULL) {
+ assertTrue(ai->ai_addrlen == sizeof(struct sockaddr_in),
+ "Sockaddr wrong length, expected %zu got %u", sizeof(struct sockaddr_in), ai->ai_addrlen);
+ memcpy(result, ai->ai_addr, ai->ai_addrlen);
+ result->sin_port = htons(port);
+ addr = (struct sockaddr *) result;
+ }
+ break;
+ }
+
+ case PF_INET6: {
+ struct sockaddr_in6 *result = parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6));
+ assertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(struct sockaddr_in6));
+ if (result != NULL) {
+ assertTrue(ai->ai_addrlen == sizeof(struct sockaddr_in6),
+ "Sockaddr wrong length, expected %zu got %u", sizeof(struct sockaddr_in6), ai->ai_addrlen);
+
+ memcpy(result, ai->ai_addr, ai->ai_addrlen);
+ result->sin6_port = htons(port);
+ result->sin6_flowinfo = 0;
+ result->sin6_scope_id = 0;
+ addr = (struct sockaddr *) result;
+ }
+ break;
+ }
+
+ default: {
+ // unsupported protocol
+ addr = NULL;
+ break;
+ }
+ }
+
+ freeaddrinfo(ai);
+ }
+
+ return addr;
+}
+
+struct sockaddr_in *
+parcNetwork_SockInet4Address(const char *address, in_port_t port)
+{
+ struct sockaddr_in *result = parcMemory_AllocateAndClear(sizeof(struct sockaddr_in));
+ assertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(struct sockaddr_in));
+ if (result != NULL) {
+ result->sin_family = AF_INET;
+ result->sin_port = htons(port);
+#if defined(SIN6_LEN)
+ result->sin_len = sizeof(struct sockaddr_in);
+#endif
+ if (inet_pton(AF_INET, address, &(result->sin_addr)) == 1) {
+ return result;
+ }
+ parcMemory_Deallocate((void **) &result);
+ }
+
+ return NULL;
+}
+
+struct sockaddr_in6 *
+parcNetwork_SockInet6Address(const char *address, in_port_t port, uint32_t flowInfo, uint32_t scopeId)
+{
+ struct sockaddr_in6 *result = parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6));
+ assertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(struct sockaddr_in6));
+ if (result != NULL) {
+ result->sin6_family = AF_INET6;
+ result->sin6_port = htons(port);
+ result->sin6_flowinfo = flowInfo;
+ result->sin6_scope_id = scopeId;
+#if defined(SIN6_LEN)
+ result->sin6_len = sizeof(struct sockaddr_in6);
+#endif
+
+ if (inet_pton(AF_INET6, address, &(result->sin6_addr)) == 1) {
+ return result;
+ }
+ parcMemory_Deallocate((void **) &result);
+ }
+
+ return NULL;
+}
+
+struct sockaddr_in *
+parcNetwork_SockInet4AddressAny()
+{
+ struct sockaddr_in *result = parcMemory_AllocateAndClear(sizeof(struct sockaddr_in));
+ assertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(struct sockaddr_in));
+ if (result != NULL) {
+ result->sin_family = AF_INET;
+ result->sin_addr.s_addr = INADDR_ANY;
+#if defined(SIN6_LEN)
+ result->sin_len = sizeof(struct sockaddr_in);
+#endif
+ return result;
+ }
+ return NULL;
+}
+
+PARCBufferComposer *
+parcNetwork_SockInet4Address_BuildString(const struct sockaddr_in *address, PARCBufferComposer *composer)
+{
+ assertNotNull(address, "Parameter must be a non-null pointer to a struct sockaddr_in.");
+
+ if (address->sin_family != AF_INET) {
+ trapIllegalValue(address->sin_family, "Expected an AF_INET configured address, not %d", address->sin_family);
+ }
+
+ char buffer[INET_ADDRSTRLEN];
+ inet_ntop(address->sin_family, &address->sin_addr, buffer, INET_ADDRSTRLEN);
+ parcBufferComposer_Format(composer, "inet4://%s:%u", buffer, ntohs(address->sin_port));
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcNetwork_SockInet6Address_BuildString(const struct sockaddr_in6 *address, PARCBufferComposer *composer)
+{
+ assertNotNull(address, "Parameter must be a non-null pointer to a struct sockaddr_in.");
+
+ if (address->sin6_family != AF_INET6) {
+ trapIllegalValue(address->sin_family, "Expected an AF_INET6 configured address, not %d", address->sin6_family);
+ }
+
+ char buffer[INET6_ADDRSTRLEN];
+ inet_ntop(address->sin6_family, &address->sin6_addr, buffer, INET6_ADDRSTRLEN);
+
+ parcBufferComposer_Format(composer, "inet6://[%s%%%u]:%u",
+ buffer,
+ address->sin6_scope_id,
+ ntohs(address->sin6_port));
+
+ return composer;
+}
+
+PARCBufferComposer *
+parcNetwork_LinkAddress_BuildString(const unsigned char *address, size_t length, PARCBufferComposer *composer)
+{
+ parcBufferComposer_PutString(composer, "link://");
+ for (size_t i = 0; i < length; i++) {
+ if (i > 0) {
+ parcBufferComposer_PutString(composer, "-");
+ }
+ parcBufferComposer_Format(composer, "%02x", address[i]);
+ }
+ return composer;
+}
+
+struct sockaddr_in *
+parcNetwork_ParseInet4Address(const char *addressURI)
+{
+ struct sockaddr_in *result = NULL;
+
+ PARCURI *uri = parcURI_Parse(addressURI);
+ if (strcmp("inet4", parcURI_GetScheme(uri)) == 0) {
+ }
+ parcURI_Release(&uri);
+
+ return result;
+}
+
+static PARCBuffer *
+_parseMAC48AddressDashOrColon(const char *address, PARCBuffer *result)
+{
+ char *nextP = NULL;
+
+ const char *p = address;
+
+ int i = 0;
+ for (i = 0; i < 6; i++) {
+ long value = strtol(p, &nextP, 16);
+ if (nextP == p || (*nextP != ':' && *nextP != '-' && *nextP != 0)) {
+ result = NULL;
+ break;
+ }
+ parcBuffer_PutUint8(result, (uint8_t) value);
+
+ p = nextP + 1;
+ }
+
+ if (i != 6) {
+ result = NULL;
+ }
+
+ return result;
+}
+
+static PARCBuffer *
+_parseMAC48AddressDot(const char *address, PARCBuffer *result)
+{
+ char *nextP = NULL;
+
+ const char *p = address;
+
+ int i = 0;
+ for (i = 0; i < 3; i++) {
+ long value = strtol(p, &nextP, 16);
+ if (nextP == p || (*nextP != '.' && *nextP != 0)) {
+ result = NULL;
+ break;
+ }
+ parcBuffer_PutUint16(result, (uint16_t) value);
+
+ p = nextP + 1;
+ }
+
+ if (i != 3) {
+ result = NULL;
+ }
+
+ return result;
+}
+
+bool
+parcNetwork_ParseMAC48Address(const char *address, PARCBuffer *buffer)
+{
+ bool result = false;
+
+ size_t originalPosition = parcBuffer_Position(buffer);
+
+ if (strchr(address, '-') != NULL || strchr(address, ':') != NULL) {
+ if (_parseMAC48AddressDashOrColon(address, buffer) != NULL) {
+ result = true;
+ }
+ }
+
+ if (strchr(address, '.') != NULL) {
+ if (_parseMAC48AddressDot(address, buffer) != NULL) {
+ result = true;
+ }
+ ;
+ }
+
+ if (result == false) {
+ parcBuffer_SetPosition(buffer, originalPosition);
+ }
+
+ return result;
+}
+
+PARCBuffer *
+parcNetwork_ParseLinkAddress(const char *address)
+{
+ if (strncmp("link://", address, 7) == 0) {
+ PARCBuffer *result = parcBuffer_Allocate(7);
+
+ if (parcNetwork_ParseMAC48Address(&address[7], result) == false) {
+ parcBuffer_Release(&result);
+ trapIllegalValue(address, "Syntax error '%s'", address);
+ }
+
+ return parcBuffer_Flip(result);
+ }
+
+ trapIllegalValue(address, "Bad scheme '%s'", address);
+}
+
+bool
+parcNetwork_Inet4Equals(const struct sockaddr_in *x, const struct sockaddr_in *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+ if (x->sin_family == y->sin_family) {
+ if (x->sin_addr.s_addr == y->sin_addr.s_addr) {
+ if (x->sin_port == y->sin_port) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/*
+ * Returns true for ::1 address, false otherwise
+ *
+ * The address is in network byte order
+ *
+ * @return true The address is local
+ * @return false The address is not local
+ */
+static bool
+_isInet6Loopback(struct sockaddr_in6 *sin6)
+{
+ if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Returns true if the address is on the 127.0.0.0/8 network
+ *
+ * The address is expected to be in network byte order
+ *
+ * @param [in] sin4 A pointer to a sockaddr_in containing an IPv4 address.
+ *
+ * @return true Address on 127.0.0.0/8
+ * @return false Not a 127.0.0.0/8
+ */
+static bool
+_isInet4Loopback(struct sockaddr_in *sin4)
+{
+ uint32_t hostorder = htonl(sin4->sin_addr.s_addr);
+ if ((hostorder & 0xFF000000) == 0x7F000000) {
+ return true;
+ }
+ return false;
+}
+
+bool
+parcNetwork_IsSocketLocal(struct sockaddr *sock)
+{
+ assertNotNull(sock, "Parameter sock must be non-null");
+ bool isLocal = false;
+
+ switch (sock->sa_family) {
+ case PF_LOCAL:
+ isLocal = true;
+ break;
+
+ case PF_INET:
+ isLocal = _isInet4Loopback((struct sockaddr_in *) sock);
+ break;
+
+ case PF_INET6:
+ isLocal = _isInet6Loopback((struct sockaddr_in6 *) sock);
+ break;
+
+ default:
+ break;
+ }
+
+ return isLocal;
+}
diff --git a/libparc/parc/algol/parc_Network.h b/libparc/parc/algol/parc_Network.h
new file mode 100644
index 00000000..efd5e632
--- /dev/null
+++ b/libparc/parc/algol/parc_Network.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 parc_Network.h
+ * @ingroup networking
+ * @brief Basic Networking Support
+ *
+ */
+#ifndef libparc_parc_Networking_h
+#define libparc_parc_Networking_h
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Buffer.h>
+
+#ifndef INPORT_ANY
+#define INPORT_ANY 0
+#endif
+
+#ifdef __ANDROID__
+typedef uint16_t in_port_t;
+#endif
+
+/**
+ * Parses any string in to an address, if possible
+ *
+ * The string may be an IPv6, IPv6 or hostname. If the string does not match an IPv4 or IPv6 nominal format,
+ * it will try to resolve the string as a hostname. If that fails, the function will return NULL.
+ *
+ * IMPORTANT: the returned pointer is allocated with <code>parcMemory_Allocate()</code> and you must use <code>parcMemory_Deallocate()</code>.
+ *
+ * @param [in] address An IPv4, IPv6, or hostname
+ * @param [in] port the port address
+ *
+ * @return NULL Could not parse the address or resolve as a hostname
+ * @return non-NULL a valid sockaddr. You shoule examine `sockaddr->sa_family` to determine IPv4 or IPv6.
+ *
+ * Example:
+ * @code
+ * {
+ * struct sockaddr *addr;
+ * addr = parcNetwork_SockAddress("1.2.3.4", 555);
+ * assertTrue(addr && addr->sa_family == AF_INET, "Addr not IPv4 for a dotted quad.");
+ * struct sockaddr_in *addr_in = (struct sockaddr_in *) addr;
+ * // ...
+ * parcMemory_Deallocate((void **)&addr);
+ *
+ * addr = parcNetwork_SockAddress("fe80::aa20:66ff:fe00:314a", 555);
+ * assertTrue(addr && addr->sa_family == AF_INET6, "Addr not IPv6.");
+ * struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *) addr;
+ * // ...
+ * parcMemory_Deallocate((void **)&addr);
+ *
+ * addr = parcNetwork_SockAddress("alpha.parc.com", 555);
+ * assertTrue(addr && addr->sa_family == AF_INET, "Addr not IPv4 hostname with only ipv4 address.");
+ * // ...
+ * parcMemory_Deallocate((void **)&addr);
+ *
+ * addr = parcNetwork_SockAddress("Over the rainbow, way up high", 555);
+ * assertNull(addr, "Addr no null for bogus name.");
+ *
+ * }
+ * @endcode
+ */
+struct sockaddr *parcNetwork_SockAddress(const char *address, in_port_t port);
+
+/**
+ * Compose an allocated sockaddr_in structure.
+ *
+ *
+ * @param [in] address An IPv4, IPv6, or hostname
+ * @param [in] port the port address
+ * @return A pointer to an allocated struct sockaddr_in which must be freed by <code>parcMemory_Deallocate()</code>, or NULL on error.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+struct sockaddr_in *parcNetwork_SockInet4Address(const char *address, in_port_t port);
+
+/**
+ * Compose an allocated sockaddr_in6 structure.
+ *
+ *
+ * @param [in] address An IPv4, IPv6, or hostname
+ * @param [in] port the port address
+ * @param flowInfo
+ * @param scopeId
+ * @return A pointer to an allocated sockaddr_in6 structure that must be freed via parcMemory_Deallocate(), or NULL on error.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+struct sockaddr_in6 *parcNetwork_SockInet6Address(const char *address, in_port_t port, uint32_t flowInfo, uint32_t scopeId);
+
+/**
+ * Allocate a struct sockaddr_in
+ *
+ * @return A pointer to an allocated struct sockaddr_in which must be freed by {@link parcMemory_Deallocate()}, or NULL on error.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+struct sockaddr_in *parcNetwork_SockInet4AddressAny(void);
+
+/**
+ * Append the string representation of the `struct sockaddr_in` to a {@link PARCBufferComposer}.
+ *
+ * The position of the `PARCBufferComposer` is incremented by the number characters necessary to represent the `struct sockaddr_in`
+ *
+ * @param [in] address An IPv4, IPv6, or hostname
+ * @param [in,out] composer The instance of `PARCBufferComposer` to be modified.
+ * @return return
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferComposer *parcNetwork_SockInet4Address_BuildString(const struct sockaddr_in *address, PARCBufferComposer *composer);
+
+/**
+ * Append the string representation of the `struct sockaddr_in6` to a `PARCBufferComposer`.
+ *
+ * The position of the `PARCBufferComposer` is incremented by the number characters necessary to represent the `struct sockaddr_in6`
+ *
+ *
+ * @param [in] address A pointer to the spckaddr_in6 to append.
+ * @param [in,out] composer a POinter to the `PARCBufferComposer` to modify.
+ * @return A pointer to the @p composer.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferComposer *parcNetwork_SockInet6Address_BuildString(const struct sockaddr_in6 *address, PARCBufferComposer *composer);
+
+/**
+ * The standard (IEEE 802) format for printing MAC-48 addresses in human-friendly form is six groups of two hexadecimal digits,
+ * separated by hyphens (-) or colons (:), in transmission order (e.g. `01-23-45-67-89-ab` or `01:23:45:67:89:ab`).
+ * This form is also commonly used for EUI-64.
+ * Another convention used by networking equipment uses three groups of four hexadecimal digits separated by dots (.)
+ * (e.g. `0123.4567.89ab` ), again in transmission order.
+ *
+ * @param [in] address A pointer to the adress of the string.
+ * @param [in] length The size of the buffer
+ * @param [in] composer A pointer to the buffer.
+ * @return A pointer to the `PARCBufferComposer` containing the built string.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBufferComposer *parcNetwork_LinkAddress_BuildString(const unsigned char *address, size_t length, PARCBufferComposer *composer);
+
+/**
+ * Parse a link address, expressed as a nul-terminated C string of the form
+ * `link://` followed by hexadecimal numbers representing single byte values,
+ * each value separated by either a ':' or '-' character.
+ *
+ * The standard (IEEE 802) format for printing MAC-48 addresses in human-friendly form is six groups of two hexadecimal digits,
+ * separated by hyphens (-) or colons (:), in transmission order (e.g. `01-23-45-67-89-ab` or `01:23:45:67:89:ab`).
+ * This form is also commonly used for EUI-64.
+ *
+ * Another convention used by networking equipment uses three groups of four hexadecimal digits separated by dots (.)
+ * (e.g. `0123.4567.89ab` ), again in transmission order.
+ *
+ * @param address A null-terminated C string of the form `link://` followed single byte values separated by ':' or '-'.
+ * @return A PARCBuffer instance containing the parsed bytes of the link address.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * PARCBuffer *address = parcNetwork_ParseLinkAddress("link://32-00-14-06-30-60");
+ *
+ * }
+ * @endcode
+ *
+ * @see parcNetwork_ParseMAC48Address
+ */
+PARCBuffer *parcNetwork_ParseLinkAddress(const char *address);
+
+/**
+ * Parse a MAC-48 address, expressed as a nul-terminated C string of the standard (IEEE 802)
+ * format for printing MAC-48 addresses in human-friendly form is six groups of two hexadecimal digits,
+ * separated by hyphens (-) or colons (:), in transmission order (e.g. `01-23-45-67-89-ab` or `01:23:45:67:89:ab`).
+ * This form is also commonly used for EUI-64.
+ *
+ * Another convention used by networking equipment uses three groups of four hexadecimal digits separated by dots (.)
+ * (e.g. `0123.4567.89ab` ), again in transmission order.
+ *
+ * @param [in] address A null-terminated C string of the form `link://` followed single byte values separated by ':' or '-'.
+ * @param [out] result A pointer to a `PARCBuffer` for the result.
+ * @return `true` If the address was successfully parsed.
+ * @return `false` if the address was not successfully parsed. The output PARCBuffer is unmodified.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * PARCBuffer *address = parcNetwork_ParseMAC48Address("32-00-14-06-30-60");
+ *
+ * }
+ * @endcode
+ */
+bool parcNetwork_ParseMAC48Address(const char *address, PARCBuffer *result);
+
+/**
+ * Return the address parsed from @p addressURI.
+ *
+ * @param [in] addressURI
+ * @return A pointer to the `sockaddr_in`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+struct sockaddr_in *parcNetwork_ParseInet4Address(const char *addressURI);
+
+/**
+ * Determines if a socket is local
+ *
+ * A socket is local if: (a) PF_LOCAL/AF_UNIX, or (b) PF_INET and on the 127.0.0.0/8 network,
+ * or (c) PF_INET6 and equal to the ::1 address. Anything else is considered non-local.
+ *
+ * @param [in] sock A socket structure
+ *
+ * @return `true` The socket represents a local/loopback address
+ * @return `false` The socket is not a local/loopback address
+ *
+ * Example:
+ * @code
+ * {
+ * struct sockaddr *s = parcNetwork_SockAddress("127.1.1.1", 5900);
+ * assertTrue(parcNetwork_IsSocketLocal(s), "This will not assert");
+ * parcMemory_Deallocate((void **)&s);
+ * }
+ * @endcode
+ */
+bool parcNetwork_IsSocketLocal(struct sockaddr *sock);
+
+/**
+ * Return true if two `sockaddr_in` instances are equal.
+ *
+ * The equality function that this evaluates must implement the following equivalence relations on non-null instances:
+ *
+ * * It is reflexive: for any non-null reference value x, parcNetwork_Inet4Equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, parcNetwork_Inet4Equals(x, y) must return true if and only if
+ * parcNetwork_Inet4Equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * parcNetwork_Inet4Equals(x, y) returns true and
+ * parcNetwork_Inet4Equals(y, z) returns true,
+ * then parcNetwork_Inet4Equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of parcNetwork_Inet4Equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, equals(x, NULL)) must return false.
+ *
+ * @param [in] x A pointer to a struct sockaddr_in instance.
+ * @param [in] y A pointer to a struct sockaddr_in instance.s
+ * @return true the given sockaddr_in instances are equal.
+ * @return false the given sockaddr_in instances are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcNetwork_Inet4Equals(const struct sockaddr_in *x, const struct sockaddr_in *y);
+#endif // libparc_parc_Networking_h
diff --git a/libparc/parc/algol/parc_Object.c b/libparc/parc/algol/parc_Object.c
new file mode 100644
index 00000000..578f1e1a
--- /dev/null
+++ b/libparc/parc/algol/parc_Object.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 <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <pthread.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Hash.h>
+#include <parc/concurrent/parc_AtomicUint64.h>
+
+typedef struct parc_object_locking {
+ pthread_mutex_t lock;
+ pthread_cond_t notification;
+ pthread_t locker;
+} _PARCObjectLocking;
+
+/*
+ * This is the per-object header.
+ * The size of this structure must be less than or equal to the value used in the parcObject_PrefixLength macro.
+ */
+typedef struct object_header {
+#define PARCObject_HEADER_MAGIC_GUARD_NUMBER 0x0ddFadda
+ uint32_t magicGuardNumber;
+ bool isAllocated;
+ bool barrier;
+ PARCReferenceCount references;
+ const PARCObjectDescriptor *descriptor;
+
+ // The locking member points to the locking structure or is NULL if the object does not support locking.
+ _PARCObjectLocking *locking;
+
+ // Currently every object is lockable, but at some point in the future this will be controlled by the descriptor.
+ _PARCObjectLocking lock;
+
+ void *data[];
+} _PARCObjectHeader;
+
+/*
+ * Increment/decrement a pointer by the given value.
+ *
+ * @param [in] base The base pointer.
+ * @param [in] increment The value of the pointer increment.
+ *
+ * @return void* The updated pointer
+ */
+static inline void *
+_pointerAdd(const void *base, const size_t increment)
+{
+ void *result = (void *) &((char *) base)[increment];
+ return result;
+}
+
+/*
+ * Compute the size of the prefix as the number of bytes necessary
+ * to fit the object header (with padding), and any additional per-object data, into allocated memory,
+ * such that the first address after the header and any additional per-object data,
+ * is aligned according to the value of the alignment parameter.
+ *
+ * For example, if the object header is 5 bytes long, and the alignment is 4 (bytes),
+ * then the necessary number of bytes to fit the header
+ * (and yet maintain the proper alignment for the first memory location after the header) is 8.
+ *
+ * @param [in] alignment Cache alignment
+ *
+ * @return The size of the object header as the number of bytes necessary to fit the header (with padding) into allocated memory.
+ */
+static inline size_t
+_parcObject_PrefixLength(const PARCObjectDescriptor *descriptor)
+{
+ return parcObject_PrefixLength(descriptor->objectAlignment);
+}
+
+/*
+ * Given the memory address, return a pointer to the corresponding _PARCObjectHeader structure.
+ *
+ * @param [in] object The base pointer to the object.
+ *
+ * @return A _PARCObjectHeader struct encapsulating the object's header information.
+ */
+static inline _PARCObjectHeader *
+_parcObject_Header(const PARCObject *object)
+{
+ return _pointerAdd(object, -sizeof(_PARCObjectHeader));
+}
+
+static inline const PARCObjectDescriptor *
+_parcObject_Descriptor(const PARCObject *object)
+{
+ return (_parcObject_Header(object)->descriptor);
+}
+
+static inline _PARCObjectLocking *
+_parcObjectHeader_Locking(const PARCObject *object)
+{
+ return _parcObject_Header(object)->locking;
+}
+
+static inline bool
+_parcObjectHeader_IsValid(const _PARCObjectHeader *header, const PARCObject *object)
+{
+ bool result = true;
+
+ if ((intptr_t) header >= (intptr_t) object) {
+ result = false;
+ } else if (header->magicGuardNumber != PARCObject_HEADER_MAGIC_GUARD_NUMBER) {
+ result = false;
+ } else if (header->references == 0) {
+ result = false;
+ }
+
+ return result;
+}
+
+/*
+ * Compute the origin of the allocated memory.
+ *
+ * This will be greater than the start of the object header.
+ * due to alignment requirements causing the object header to be offset from the origin.
+ */
+static inline void *
+_parcObject_Origin(const PARCObject *object)
+{
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ return _pointerAdd(object, -_parcObject_PrefixLength(header->descriptor));
+}
+
+static inline PARCObjectEquals *
+_parcObject_ResolveEquals(const PARCObjectDescriptor *descriptor)
+{
+ while (descriptor->equals == NULL) {
+ descriptor = descriptor->super;
+ }
+ return descriptor->equals;
+}
+
+static inline PARCObjectCopy *
+_parcObject_ResolveCopy(const PARCObjectDescriptor *descriptor)
+{
+ while (descriptor->copy == NULL) {
+ descriptor = descriptor->super;
+ }
+ return descriptor->copy;
+}
+
+static inline PARCObjectToString *
+_parcObject_ResolveToString(const PARCObjectDescriptor *descriptor)
+{
+ while (descriptor->toString == NULL) {
+ descriptor = descriptor->super;
+ }
+ return descriptor->toString;
+}
+
+static inline PARCObjectToJSON *
+_parcObject_ResolveToJSON(const PARCObjectDescriptor *descriptor)
+{
+ while (descriptor->toJSON == NULL) {
+ descriptor = descriptor->super;
+ }
+ return descriptor->toJSON;
+}
+
+static bool
+_parcObject_Destructor(const PARCObjectDescriptor *descriptor, PARCObject **object)
+{
+ if (descriptor != NULL) {
+ if (descriptor->destructor != NULL) {
+ return descriptor->destructor(object);
+ } else if (descriptor->destroy != NULL) {
+ descriptor->destroy(object);
+ }
+ }
+
+ return true;
+}
+
+static int
+_parcObject_Compare(const PARCObject *self, const PARCObject *other)
+{
+ _PARCObjectHeader *header = _parcObject_Header(self);
+ size_t length = header->descriptor->objectSize;
+ int result = memcmp(self, other, length);
+ return result;
+}
+
+static PARCObject *
+_parcObject_Copy(const PARCObject *object)
+{
+ _PARCObjectHeader *header = _parcObject_Header(object);
+ size_t length = header->descriptor->objectSize;
+
+ void *result = parcObject_CreateInstanceImpl(header->descriptor);
+ memcpy(result, object, length);
+ parcObject_OptionalAssertValid(result);
+ return result;
+}
+
+static bool
+_parcObject_Equals(const PARCObject *x, const PARCObject *y)
+{
+ _PARCObjectHeader *header = _parcObject_Header(x);
+
+ bool result = memcmp(x, y, header->descriptor->objectSize) == 0;
+
+ return result;
+}
+
+static char *
+_parcObject_ToString(const PARCObject *object)
+{
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ char *string;
+ int nwritten = asprintf(&string,
+ "Object@%p { .references=%" PRId64 ", .objectLength = %zd, .objectAlignment=%u } data %p\n",
+ (void *) header,
+ header->references, header->descriptor->objectSize, header->descriptor->objectAlignment, object);
+ assertTrue(nwritten >= 0, "Error calling asprintf");
+ char *result = parcMemory_StringDuplicate(string, strlen(string));
+ free(string);
+ return result;
+}
+
+static PARCJSON *
+_parcObject_ToJSON(const PARCObject *object)
+{
+ _PARCObjectHeader *prefix = _parcObject_Header(object);
+
+ PARCJSON *json = parcJSON_Create();
+
+ parcJSON_AddInteger(json, "references", prefix->references);
+ parcJSON_AddInteger(json, "objectLength", prefix->descriptor->objectSize);
+ parcJSON_AddInteger(json, "objectAlignment", prefix->descriptor->objectAlignment);
+
+ char *addressString;
+ int nwritten = asprintf(&addressString, "%p", object);
+ assertTrue(nwritten >= 0, "Error calling asprintf");
+
+ parcJSON_AddString(json, "address", addressString);
+
+ return json;
+}
+
+static PARCHashCode
+_parcObject_HashCode(const PARCObject *object)
+{
+ _PARCObjectHeader *header = _parcObject_Header(object);
+ return parcHashCode_Hash(object, header->descriptor->objectSize);
+}
+
+static void
+_parcObject_Display(const PARCObject *object, const int indentation)
+{
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ parcDisplayIndented_PrintLine(indentation, "PARCObject@%p @%p={ .name=%s .references=%zd }\n",
+ object, header, header->descriptor->name, header->references);
+}
+
+const PARCObjectDescriptor
+parcObject_DescriptorName(PARCObject) =
+{
+ .name = "PARCObject",
+ .destroy = NULL,
+ .destructor = NULL,
+ .release = NULL,
+ .copy = _parcObject_Copy,
+ .toString = _parcObject_ToString,
+ .equals = _parcObject_Equals,
+ .compare = _parcObject_Compare,
+ .hashCode = _parcObject_HashCode,
+ .toJSON = _parcObject_ToJSON,
+ .display = _parcObject_Display,
+ .super = NULL,
+ .isLockable = true,
+ .objectSize = 0,
+ .objectAlignment = sizeof(void *)
+};
+
+bool
+parcObject_IsValid(const PARCObject *object)
+{
+ bool result = true;
+
+ if (object == NULL) {
+ result = false;
+ } else {
+ if (_parcObjectHeader_IsValid(_parcObject_Header(object), object) == false) {
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcObjectHeader_OptionalAssertValid(_instance_)
+#else
+# define parcObjectHeader_OptionalAssertValid(_instance_) _parcObjectHeader_AssertValid(_instance_)
+#endif
+
+static inline void
+_parcObjectHeader_AssertValid(const _PARCObjectHeader *header, const PARCObject *object)
+{
+ trapIllegalValueIf(header->magicGuardNumber != PARCObject_HEADER_MAGIC_GUARD_NUMBER, "PARCObject@%p is corrupt.", object);
+ trapIllegalValueIf(header->descriptor == NULL, "PARCObject@%p descriptor cannot be NULL.", object);
+ if (header->descriptor->isLockable) {
+ trapIllegalValueIf(header->locking == NULL, "PARCObject@%p is corrupt. Is Lockable but no locking structure", object);
+ }
+}
+
+static inline void
+_parcObject_AssertValid(const PARCObject *object)
+{
+ trapIllegalValueIf(object == NULL, "PARCObject must be a non-null pointer.");
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+ _parcObjectHeader_AssertValid(header, object);
+}
+
+void
+parcObject_AssertValid(const PARCObject *object)
+{
+ _parcObject_AssertValid(object);
+}
+
+PARCObject *
+parcObject_Acquire(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ parcAtomicUint64_Increment(&header->references);
+
+ return (PARCObject *) object;
+}
+
+static inline PARCObjectCompare *
+_parcObject_ResolveCompare(const PARCObjectDescriptor *descriptor)
+{
+ while (descriptor->compare == NULL) {
+ descriptor = descriptor->super;
+ }
+ return descriptor->compare;
+}
+
+int
+parcObject_Compare(const PARCObject *x, const PARCObject *y)
+{
+ int result = 0;
+ if ((x == NULL) || (y == NULL)) {
+ result = 0;
+ if (x != NULL) {
+ result = 1;
+ } else if (y != NULL) {
+ result = -1;
+ }
+ return result;
+ }
+
+ parcObject_OptionalAssertValid(x);
+ parcObject_OptionalAssertValid(y);
+
+ PARCObjectCompare *compare = _parcObject_ResolveCompare(_parcObject_Descriptor(x));
+ result = compare(x, y);
+
+ return result;
+}
+
+bool
+parcObject_IsInstanceOf(const PARCObject *object, const PARCObjectDescriptor *descriptor)
+{
+ bool result = false;
+
+ if (object != NULL) {
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ if (_parcObjectHeader_IsValid(header, object)) {
+ const PARCObjectDescriptor *d = _parcObject_Descriptor(object);
+
+ while (result == false) {
+ if (d == descriptor) {
+ result = true;
+ }
+ d = d->super;
+ }
+ }
+ }
+
+ return result;
+}
+
+bool
+parcObject_Equals(const PARCObject *x, const PARCObject *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x != NULL && y != NULL) {
+ _PARCObjectHeader *xHeader = _parcObject_Header(x);
+ _PARCObjectHeader *yHeader = _parcObject_Header(y);
+
+ if (xHeader->descriptor == yHeader->descriptor) {
+ PARCObjectEquals *equals = _parcObject_ResolveEquals(xHeader->descriptor);
+ result = equals(x, y);
+ }
+ }
+
+ return result;
+}
+
+static inline PARCObjectHashCode *
+_parcObject_ResolveHashCode(const PARCObjectDescriptor *descriptor)
+{
+ while (descriptor->hashCode == NULL) {
+ descriptor = descriptor->super;
+ }
+ return descriptor->hashCode;
+}
+
+PARCHashCode
+parcObject_HashCode(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ PARCObjectHashCode *hashCode = _parcObject_ResolveHashCode(_parcObject_Descriptor(object));
+
+ return hashCode(object);
+}
+
+static inline PARCObjectDisplay *
+_parcObject_ResolveDisplay(const PARCObjectDescriptor *descriptor)
+{
+ while (descriptor->display == NULL) {
+ descriptor = descriptor->super;
+ }
+ return descriptor->display;
+}
+
+void
+parcObject_Display(const PARCObject *object, const int indentation)
+{
+ parcObject_OptionalAssertValid(object);
+
+ PARCObjectDisplay *display = _parcObject_ResolveDisplay(_parcObject_Descriptor(object));
+
+ display(object, indentation);
+}
+
+char *
+parcObject_ToString(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ PARCObjectToString *toString = _parcObject_ResolveToString(_parcObject_Descriptor(object));
+
+ return toString(object);
+}
+
+PARCJSON *
+parcObject_ToJSON(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ PARCObjectToJSON *toJSON = _parcObject_ResolveToJSON(_parcObject_Descriptor(object));
+ return toJSON(object);
+}
+
+PARCObject *
+parcObject_CreateAndClearInstanceImpl(const PARCObjectDescriptor *descriptor)
+{
+ PARCObject *result = parcObject_CreateInstanceImpl(descriptor);
+ memset(result, 0, descriptor->objectSize);
+ return result;
+}
+
+static pthread_once_t _parcObject_GlobalLockAttributesInitialized = PTHREAD_ONCE_INIT;
+static pthread_mutexattr_t _parcObject_GlobalLockAttributes;
+
+static void
+_parcObject_InitializeGobalLockAttributes(void)
+{
+ pthread_mutexattr_init(&_parcObject_GlobalLockAttributes);
+ pthread_mutexattr_settype(&_parcObject_GlobalLockAttributes, PTHREAD_MUTEX_ERRORCHECK);
+}
+
+static inline void
+_parcObject_InitializeLocking(_PARCObjectLocking *locking)
+{
+ if (locking != NULL) {
+ pthread_once(&_parcObject_GlobalLockAttributesInitialized, _parcObject_InitializeGobalLockAttributes);
+
+ pthread_mutex_init(&locking->lock, &_parcObject_GlobalLockAttributes);
+ pthread_cond_init(&locking->notification, NULL);
+
+ locking->locker = (pthread_t) NULL;
+ }
+}
+
+static inline _PARCObjectHeader *
+_parcObjectHeader_InitAllocated(_PARCObjectHeader *header, const PARCObjectDescriptor *descriptor)
+{
+ header->magicGuardNumber = PARCObject_HEADER_MAGIC_GUARD_NUMBER;
+ header->barrier = false;
+ header->references = 1;
+ header->descriptor = (PARCObjectDescriptor *) descriptor;
+ header->isAllocated = true;
+
+ if (header->descriptor->isLockable) {
+ header->locking = &header->lock;
+ _parcObject_InitializeLocking(header->locking);
+ } else {
+ header->locking = NULL;
+ }
+
+ return header;
+}
+
+static inline _PARCObjectHeader *
+_parcObjectHeader_InitUnallocated(_PARCObjectHeader *header, const PARCObjectDescriptor *descriptor)
+{
+ _parcObjectHeader_InitAllocated(header, descriptor);
+ header->isAllocated = false;
+
+ return header;
+}
+
+PARCObject *
+parcObject_WrapImpl(void *memory, const PARCObjectDescriptor *descriptor)
+{
+ size_t prefixLength = _parcObject_PrefixLength(descriptor);
+ PARCObject *object = _pointerAdd(memory, prefixLength);
+
+ _parcObjectHeader_InitUnallocated(_parcObject_Header(object), descriptor);
+
+ return object;
+}
+
+PARCObject *
+parcObject_CreateInstanceImpl(const PARCObjectDescriptor *descriptor)
+{
+ size_t prefixLength = _parcObject_PrefixLength(descriptor);
+ size_t totalMemoryLength = prefixLength + descriptor->objectSize;
+
+ void *origin = NULL;
+ parcMemory_MemAlign(&origin, sizeof(void *), totalMemoryLength);
+
+ if (origin == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ PARCObject *object = _pointerAdd(origin, prefixLength);
+
+ _parcObjectHeader_InitAllocated(_parcObject_Header(object), descriptor);
+
+ errno = 0;
+ return object;
+}
+
+PARCObject *
+parcObject_InitInstanceImpl(PARCObject *object, const PARCObjectDescriptor *descriptor)
+{
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ _parcObjectHeader_InitUnallocated(header, descriptor);
+ return object;
+}
+
+PARCObject *
+parcObject_InitAndClearInstanceImpl(PARCObject *object, const PARCObjectDescriptor *descriptor)
+{
+ parcObject_InitInstanceImpl(object, descriptor);
+
+ memset(object, 0, descriptor->objectSize);
+ return object;
+}
+
+PARCObject *
+parcObject_Copy(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ PARCObjectCopy *copy = _parcObject_ResolveCopy(_parcObject_Descriptor(object));
+ return copy(object);
+}
+
+PARCReferenceCount
+parcObject_Release(PARCObject **objectPointer)
+{
+ PARCObject *object = *objectPointer;
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ trapIllegalValueIf(header->references == 0, "PARCObject@%p references must be > 0", object);
+
+ PARCReferenceCount result = parcAtomicUint64_Decrement(&header->references);
+
+ if (result == 0) {
+ if (_parcObject_Destructor(header->descriptor, objectPointer)) {
+ if (header->locking != NULL) {
+ pthread_cond_destroy(&header->locking->notification);
+ }
+ if (header->isAllocated) {
+ void *origin = _parcObject_Origin(object);
+ parcMemory_Deallocate(&origin);
+ }
+ assertNotNull(*objectPointer, "Class implementation unnecessarily clears the object pointer.");
+ } else {
+ assertNull(*objectPointer, "Class implementation must clear the object pointer.");
+ }
+ }
+
+ *objectPointer = NULL;
+ return result;
+}
+
+PARCReferenceCount
+parcObject_GetReferenceCount(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ return header->references;
+}
+
+const PARCObjectDescriptor *
+parcObject_GetDescriptor(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ return header->descriptor;
+}
+
+const PARCObjectDescriptor *
+parcObject_SetDescriptor(PARCObject *object, const PARCObjectDescriptor *descriptor)
+{
+ parcObject_OptionalAssertValid(object);
+ assertNotNull(descriptor, "PARCObjectDescriptor cannot be NULL.");
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ const PARCObjectDescriptor *result = header->descriptor;
+ header->descriptor = (PARCObjectDescriptor *) descriptor;
+
+ return result;
+}
+
+PARCObjectDescriptor *
+parcObjectDescriptor_Create(const char *name,
+ size_t objectSize,
+ unsigned int objectAlignment,
+ bool isLockable,
+ PARCObjectDestructor *destructor,
+ PARCObjectRelease *release,
+ PARCObjectCopy *copy,
+ PARCObjectToString *toString,
+ PARCObjectEquals *equals,
+ PARCObjectCompare *compare,
+ PARCObjectHashCode *hashCode,
+ PARCObjectToJSON *toJSON,
+ PARCObjectDisplay *display,
+ const PARCObjectDescriptor *superType,
+ PARCObjectTypeState *typeState)
+{
+ assertNotNull(superType, "Supertype descriptor cannot be NULL.");
+
+ PARCObjectDescriptor *result = parcMemory_AllocateAndClear(sizeof(PARCObjectDescriptor));
+ if (result != NULL) {
+ strncpy(result->name, name, sizeof(result->name) - 1);
+ result->name[sizeof(result->name) - 1] = 0;
+ result->destroy = NULL;
+ result->destructor = destructor;
+ result->release = release;
+ result->copy = copy;
+ result->toString = toString;
+ result->equals = equals;
+ result->compare = compare;
+ result->hashCode = hashCode;
+ result->toJSON = toJSON;
+ result->display = display;
+ result->super = superType;
+ result->objectSize = objectSize;
+ result->objectAlignment = objectAlignment;
+ result->typeState = typeState;
+ result->isLockable = isLockable;
+ }
+ return result;
+}
+
+PARCObjectDescriptor *
+parcObjectDescriptor_CreateExtension(const PARCObjectDescriptor *superType, const char *name)
+{
+ PARCObjectDescriptor *result = parcMemory_AllocateAndClear(sizeof(PARCObjectDescriptor));
+ *result = *superType;
+ strncpy(result->name, name, sizeof(result->name) - 1);
+ result->name[sizeof(result->name) - 1] = 0;
+ return result;
+}
+
+PARCObjectTypeState *
+parcObjectDescriptor_GetTypeState(const PARCObjectDescriptor *descriptor)
+{
+ return descriptor->typeState;
+}
+
+const PARCObjectDescriptor *
+parcObjectDescriptor_GetSuperType(const PARCObjectDescriptor *descriptor)
+{
+ return descriptor->super;
+}
+
+bool
+parcObjectDescriptor_Destroy(PARCObjectDescriptor **descriptorPointer)
+{
+ parcMemory_Deallocate(descriptorPointer);
+ return true;
+}
+
+bool
+parcObject_Unlock(const PARCObject *object)
+{
+ bool result = false;
+
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+ if (header->references > 0) {
+ _parcObjectHeader_AssertValid(header, object);
+
+ if (object != NULL) {
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ locking->locker = (pthread_t) NULL;
+ result = (pthread_mutex_unlock(&locking->lock) == 0);
+
+ assertTrue(result, "Attempted to unlock an unowned lock.");
+ }
+ }
+ }
+ return result;
+}
+
+bool
+parcObject_Lock(const PARCObject *object)
+{
+#ifndef __ANDROID__
+ extern int errno;
+#endif
+ bool result = false;
+
+ parcObject_OptionalAssertValid(object);
+
+ if (object != NULL) {
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ trapCannotObtainLockIf(pthread_equal(locking->locker, pthread_self()),
+ "Recursive locks on %p are not supported.", object);
+
+ errno = pthread_mutex_lock(&locking->lock);
+
+ if (errno == 0) {
+ locking->locker = pthread_self();
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+bool
+parcObject_TryLock(const PARCObject *object)
+{
+ bool result = false;
+
+ if (object != NULL) {
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ trapCannotObtainLockIf(pthread_equal(locking->locker, pthread_self()), "Recursive locks are not supported.");
+
+ int lockStatus = pthread_mutex_trylock(&locking->lock);
+
+ if (lockStatus == 0) {
+ result = true;
+ locking->locker = pthread_self();
+ }
+ }
+ }
+
+ return result;
+}
+
+bool
+parcObject_IsLocked(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+ bool result = false;
+
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ result = locking->locker != (pthread_t) NULL;
+ }
+
+ return result;
+}
+
+void
+parcObject_Wait(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ pthread_cond_wait(&locking->notification, &locking->lock);
+ }
+}
+
+bool
+parcObject_WaitUntil(const PARCObject *object, const struct timespec *time)
+{
+ parcObject_OptionalAssertValid(object);
+
+ bool result = false;
+
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ int waitResult = pthread_cond_timedwait(&locking->notification, &locking->lock, time);
+ if (waitResult == 0) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+bool
+parcObject_WaitFor(const PARCObject *object, const uint64_t nanoSeconds)
+{
+ parcObject_OptionalAssertValid(object);
+
+ bool result = false;
+
+ struct timeval now;
+ gettimeofday(&now, NULL);
+
+ // Convert timeval to timespec.
+ struct timespec time = {
+ .tv_sec = now.tv_sec,
+ .tv_nsec = (now.tv_usec * 1000)
+ };
+ time.tv_nsec += nanoSeconds;
+ time.tv_sec += time.tv_nsec / 1000000000;
+ time.tv_nsec = time.tv_nsec % 1000000000;
+
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ int waitResult = pthread_cond_timedwait(&locking->notification, &locking->lock, &time);
+
+ if (waitResult == 0) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+void
+parcObject_Notify(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ pthread_cond_signal(&locking->notification);
+ }
+}
+
+void
+parcObject_NotifyAll(const PARCObject *object)
+{
+ parcObject_OptionalAssertValid(object);
+
+ _PARCObjectLocking *locking = _parcObjectHeader_Locking(object);
+ if (locking != NULL) {
+ pthread_cond_broadcast(&locking->notification);
+ }
+}
+
+bool
+parcObject_BarrierSet(const PARCObject *object)
+{
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ while (__sync_bool_compare_and_swap(&header->barrier, false, true) == false) {
+ ;
+ }
+ return true;
+}
+
+bool
+parcObject_BarrierUnset(const PARCObject *object)
+{
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ while (__sync_bool_compare_and_swap(&header->barrier, true, false) == false) {
+ ;
+ }
+
+ return false;
+}
diff --git a/libparc/parc/algol/parc_Object.h b/libparc/parc/algol/parc_Object.h
new file mode 100644
index 00000000..0f3a932b
--- /dev/null
+++ b/libparc/parc/algol/parc_Object.h
@@ -0,0 +1,1504 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Object.h
+ * @ingroup memory
+ * @brief Reference Counted Object Memory
+ *
+ * An arbitrary C structure stored in allocated memory with a reference counter.
+ *
+ * When a PARC Object is created, via `parcObject_Create`, or `parcObject_Copy` it has reference count of 1.
+ *
+ * References to a PARC Object are acquired by calling `parcObject_Acquire`
+ * and once a reference is no longer needed it is released via parcObject_Release`.
+ * When the last reference is released, the memory storing the PARC Object is deallocated.
+ * Any further reference to that object or its memory is undefined.
+ *
+ * When creating a PARCObject, the caller may supply an instance of `PARCObjectDescriptor` containing
+ * configuration information used and pointers to functions that are invoked during the lifecycle of the PARC Object.
+ * Notable functions that are a finalization cleanup function for an object that will be deallocated,
+ * a clone function for an object that is being cloned,
+ * and a string generator for an object that is implementing the `ToString` function.
+ * Implementors of modules that use PARCObject supply a specification of callback
+ * functions that implement specific behaviours for interfaces using PARC Object.
+ *
+ */
+#ifndef libparc_parc_Object_h
+#define libparc_parc_Object_h
+
+#include <stdint.h>
+#include <time.h>
+
+#include <LongBow/runtime.h>
+#include <LongBow/longBow_Compiler.h>
+
+#include <parc/algol/parc_CMacro.h>
+//#include <parc/algol/parc_JSON.h>
+//#include <parc/algol/parc_HashCode.h>
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcObject_OptionalAssertValid(_instance_)
+#else
+# define parcObject_OptionalAssertValid(_instance_) parcObject_AssertValid(_instance_)
+#endif
+
+//Switch to strong type after subclasses are converted
+//typedef struct {int unused;} PARCObject;
+typedef void PARCObject;
+
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct PARCObjectDescriptor PARCObjectDescriptor;
+
+/**
+ * @define parcObject_DescriptorName(_type)
+ *
+ * Compose the token for a subtype specific name for a subtype's `PARCObjectDescriptor`
+ * which is a parameter to `parcObject_Create`.
+ *
+ * For example
+ * @code
+ * parcObject_DescriptorName(MyType)
+ * @endcode
+ *
+ * generates the token `MyType_Descriptor`
+ *
+ * Implementations should use this macro, rather than hardcode the format in their code.
+ */
+#define parcObject_DescriptorName(_type) parcCMacro_Cat(_type, _Descriptor)
+
+/**
+ * @define parcObjectDescriptor_Declaration(_type_)
+ *
+ * Create a declaration of a `PARCObjectDescriptor` implementation.
+ * To define the actual implementation, use `parcObject_Override`
+ */
+#define parcObjectDescriptor_Declaration(_type_) const PARCObjectDescriptor parcObject_DescriptorName(_type_)
+
+/**
+ * @define parcObject_Declare(_type_)
+ *
+ * Create a declaration of a `PARCObject` implementation.
+ * This causes the corresponding `typedef` to be defined
+ * and the global PARCObjectDescriptor corresponding to the declared type.
+ */
+#define parcObject_Declare(_type_) \
+ typedef struct _type_ _type_; \
+ extern parcObjectDescriptor_Declaration(_type_)
+
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_JSON.h>
+
+/**
+ * A Function that performs the final cleanup and resource deallocation when
+ * a PARC Object has no more references.
+ *
+ * This is deprecated and will be removed.
+ * Use `PARCObjectDestructor`
+ */
+typedef void (PARCObjectDestroy)(PARCObject **);
+
+/**
+ * A Function that performs the final cleanup and resource deallocation when
+ * a PARC Object has no more references.
+ *
+ * If the function returns `true` the object is automatically deallocated and destroyed.
+ * If the function returns `false` the object is not automatically deallocated and destroyed,
+ * and the responsibility for the object's state and memory are the responsibility of
+ * the `PARCObjectDestructor` function.
+ */
+typedef bool (PARCObjectDestructor)(PARCObject **);
+
+/**
+ * A Function that releases one reference to the given PARC Object.
+ * On the final release, where the number of references becomes 0,
+ * the PARCObjectDestroy function is invoked.
+ */
+typedef void (PARCObjectRelease)(PARCObject **objectPointer);
+
+/**
+ * A function that produces a deep-copy of the given PARC Object instance.
+ */
+typedef PARCObject *(PARCObjectCopy)(const PARCObject *object);
+
+/**
+ * A function that invokes the proper _Equals() function for two PARC Object instances.
+ */
+typedef bool (PARCObjectEquals)(const PARCObject *objectX, const PARCObject *objectY);
+
+/**
+ * A function that invokes the proper _Compare() functions for two PARC Object instances.
+ */
+typedef int (PARCObjectCompare)(const PARCObject *, const PARCObject *);
+
+/**
+ * A function that computes the 32-bit hashcode of the given PARC Object instance.
+ */
+typedef PARCHashCode (PARCObjectHashCode)(const PARCObject *object);
+
+/**
+ * A function that produces a C style nul-terminated string representation of the given PARC Object instance.
+ */
+typedef char *(PARCObjectToString)(const PARCObject *object);
+
+/**
+ * A function that displays a human readable representation of the given PARCObject.
+ */
+typedef void (PARCObjectDisplay)(const PARCObject *object, const int indentation);
+
+/**
+ * A function that generates a JSON representation of the given PARC Object instance.
+ */
+typedef PARCJSON *(PARCObjectToJSON)(const PARCObject *);
+
+/**
+ * Every PARCObject descriptor has a pointer to a `PARCObjectState`
+ * containing arbitrary data related to all instances sharing the descriptor.
+ */
+typedef void PARCObjectTypeState;
+
+/**
+ * Every PARC Object instance contains a pointer to an instance of this structure defining
+ * the canonical meta-data for the object.
+ */
+struct PARCObjectDescriptor {
+ char name[64];
+ PARCObjectDestroy *destroy;
+ PARCObjectDestructor *destructor;
+ PARCObjectRelease *release;
+ PARCObjectCopy *copy;
+ PARCObjectToString *toString;
+ PARCObjectEquals *equals;
+ PARCObjectCompare *compare;
+ PARCObjectHashCode *hashCode;
+ PARCObjectToJSON *toJSON;
+ PARCObjectDisplay *display;
+ const struct PARCObjectDescriptor *super;
+ size_t objectSize;
+ unsigned objectAlignment;
+ bool isLockable;
+ PARCObjectTypeState *typeState;
+};
+
+
+/**
+ * Create an allocated instance of `PARCObjectDescriptor`.
+ *
+ * @param [in] name A nul-terminated, C string containing the name of the object descriptor.
+ * @param [in] objectSize The number of bytes necessary to contain the object.
+ * @param [in] objectAlignment The alignment boundary necessary for the object, a power of 2 greater than or equal to `sizeof(void *)`
+ * @param [in] isLockable True, if this object implementation supports locking.
+ * @param [in] destructor The callback function to call when the last `parcObject_Release()` is invoked (replaces @p destroy).
+ * @param [in] release The callback function to call when `parcObject_Release()` is invoked.
+ * @param [in] copy The callback function to call when parcObject_Copy() is invoked.
+ * @param [in] toString The callback function to call when `parcObject_ToString()` is invoked.
+ * @param [in] equals The callback function to call when `parcObject_Equals()` is invoked.
+ * @param [in] compare The callback function to call when `parcObject_Compare()` is invoked.
+ * @param [in] hashCode The callback function to call when `parcObject_HashCode()` is invoked.
+ * @param [in] toJSON The callback function to call when `parcObject_ToJSON()` is invoked.
+ * @param [in] display The callback function to call when `parcObject_Display()` is invoked.
+ * @param [in] super A pointer to a `PARCObjectDescriptor` for the supertype of created `PARCObjectDescriptor`
+ * @param [in] typeState A pointer to a `PARCObjectTypeState` for the per-type data for the created `PARCObjectDescriptor`
+ *
+ * @return NULL Memory could not be allocated to store the `PARCObjectDescriptor` instance.
+ * @return non-NULL Successfully created the implementation
+ */
+PARCObjectDescriptor *parcObjectDescriptor_Create(const char *name,
+ size_t objectSize,
+ unsigned int objectAlignment,
+ bool isLockable,
+ PARCObjectDestructor *destructor,
+ PARCObjectRelease *release,
+ PARCObjectCopy *copy,
+ PARCObjectToString *toString,
+ PARCObjectEquals *equals,
+ PARCObjectCompare *compare,
+ PARCObjectHashCode *hashCode,
+ PARCObjectToJSON *toJSON,
+ PARCObjectDisplay *display,
+ const PARCObjectDescriptor *superType,
+ PARCObjectTypeState *typeState);
+
+PARCObjectDescriptor *parcObjectDescriptor_CreateExtension(const PARCObjectDescriptor *superType, const char *name);
+
+PARCObjectTypeState *parcObjectDescriptor_GetTypeState(const PARCObjectDescriptor *descriptor);
+
+const PARCObjectDescriptor *parcObjectDescriptor_GetSuperType(const PARCObjectDescriptor *descriptor);
+
+bool parcObjectDescriptor_Destroy(PARCObjectDescriptor **descriptorPointer);
+
+/**
+ * The globally available `PARCObject` descriptor.
+ */
+extern parcObjectDescriptor_Declaration(PARCObject);
+
+typedef uint64_t PARCReferenceCount;
+
+/**
+ * Assert that an instance of PARC Object is valid.
+ *
+ * If the instance is not valid, terminate via an assertion.
+ *
+ * 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] object A pointer to a PARC Object instance.
+ */
+void parcObject_AssertValid(const PARCObject *object);
+
+/**
+ * Determine if an instance of PARCObject is valid.
+ *
+ * A valid PARCObject has non-NULL, it has a reference count > 0,
+ * it is non-zero in length, and has a valid alignment.
+ *
+ * @param [in] object A pointer to a PARC Object instance.
+ *
+ * @return true The PARCObject is valid.
+ * @return true The PARCObject is invalid.
+ */
+bool parcObject_IsValid(const PARCObject *object);
+
+/**
+ * Create a new reference counted object that is a deep copy of the specified object,
+ * if possible, or, otherwise, a shallow copy of the object's total allocation memory.
+ *
+ * The reference count for the new object is 1.
+ *
+ * @param [in] object A pointer to the original object.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new reference counted object.
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * struct MyType *copy = parcObject_Copy(t);
+ * }
+ * @endcode
+ *
+ * @see parcObject_Release
+ */
+PARCObject *parcObject_Copy(const PARCObject *object);
+
+/**
+ * Compare two object instances.
+ *
+ * The comparison function in the first `PARCObjectDescriptor` parameter is used for comparison.
+ * The objects are expected to be of the same type. Thus, if the comparison function
+ * associated with the first `PARCObjectDescriptor` function is NULL, it is assumed the
+ * same holds for the second parameter. In this case, the instance pointers are compared.
+ *
+ * @param [in] x An object.
+ * @param [in] y An object.
+ *
+ * @return int The result of the comparison.
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * int compareResult = parcObject_Compare(t, t);
+ * printf("0? %d\n", compareResult);
+ *
+ * parcObject_Release(&t);
+ * }
+ * @endcode
+ */
+int parcObject_Compare(const PARCObject *x, const PARCObject *y);
+
+/**
+ * Determine if two PARCObject instances are equal.
+ *
+ * Two PARCObject instances are equal if, and only if, the instance pointers are equal.
+ *
+ * The following equivalence relations on non-null `PARCObject` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCObject_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcObject_Equals(x, y)` must return true if and only if
+ * `parcObject_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcObject_Equals(x, y)` returns true and
+ * `parcObject_Equals(y, z)` returns true,
+ * then `parcObject_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcObject_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcObject_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param x A pointer to a `PARCObject` instance.
+ * @param y A pointer to a `PARCObject` instance.
+ * @return true if the two `PARCObject` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *a = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ * struct MyType *b = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * if (parcObject_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+bool parcObject_Equals(const PARCObject *x, const PARCObject *y);
+
+/**
+ * Retrieve the hashcode of the given object.
+ *
+ * If no object implementation is provided, the hashcode is the 32-bit address
+ * of the base object pointer. Otherwise, the hashcode is computed by the
+ * provided hashcode function.
+ *
+ * @param [in] object An object.
+ *
+ * @return uint32_t The object hashcode
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * PARCHashCode hashcode = parcObject_HashCode(t);
+ * printf("Hashcode = %" PRIXPARCHashCode "\n", hashcode);
+ *
+ * parcObject_Release(&t);
+ * }
+ * @endcode
+ */
+PARCHashCode parcObject_HashCode(const PARCObject *object);
+
+/**
+ * Create a C string containing a human readable representation of the given object.
+ *
+ * @param [in] object The object from which a string representation will be generated.
+ *
+ * @return NULL Memory could not be allocated to contain the C string.
+ * @return non-NULL An allocated C string that must be deallocated via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * char *string = parcObject_ToString(t);
+ * printf("%s\n", string);
+ * parcMemory_Deallocate((void **) &string);
+ *
+ * parcObject_Release(&t);
+ * }
+ * @endcode
+ */
+char *parcObject_ToString(const PARCObject *object);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] object The object from which a JSON instance will be generated.
+ *
+ * @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
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * PARCJSON *json = parcObject_ToJSON(t);
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcObject_Release(&t);
+ * }
+ * @endcode
+ */
+PARCJSON *parcObject_ToJSON(const PARCObject *object);
+
+/**
+ * Acquire a new reference to an object.
+ *
+ * The reference count to the object is incremented.
+ *
+ * @param [in] object The object to which to refer.
+ *
+ * @return The same value as the input parameter @p object
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * struct MyType *new = parcObject_Acquire(t);
+ *
+ * parcObject_Release(&t);
+ * parcObject_Release(&new);
+ * }
+ * @endcode
+ */
+PARCObject *parcObject_Acquire(const PARCObject *object);
+
+/**
+ * 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 an invocation of `parcObject_Release` causes the last reference to
+ * the instance to be released, it calls the instance's `destructor` function
+ * specified in the `PARCObjectDescriptor` structure supplied when the instance
+ * was created (see `parcObject_Create`.
+ *
+ * The contents of the deallocated memory used for the PARC object are undefined.
+ * Do not reference the object after the last release.
+ *
+ * @param [in] objectPointer A pointer to a pointer to the instance to release.
+ *
+ * @return The number of remaining references to the object.
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * parcObject_Release(&t);
+ * }
+ * @endcode
+ *
+ * @see parcObject_Create
+ * @see parcObject_Acquire
+ */
+PARCReferenceCount parcObject_Release(PARCObject **objectPointer);
+
+/**
+ * Get the current `PARCReferenceCount` for the specified object.
+ *
+ * The reference count must always be greater than zero.
+ *
+ * @param [in] object A pointer to a valid `PARCObject` instance.
+ *
+ * @return The current reference count for the specified object.
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * PARCReferenceCount count = parcObject_GetReferenceCount(t);
+ *
+ * parcObject_Release(&t);
+ * }
+ * @endcode
+ *
+ * @see parcObject_Acquire
+ * @see parcObject_Release
+ */
+PARCReferenceCount parcObject_GetReferenceCount(const PARCObject *object);
+
+/**
+ * Print a human readable representation of the given `PARC Object.
+ *
+ * @param [in] object A pointer to the instance to display.
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * parcObject_Display(t, 0);
+ *
+ * parcObject_Release(&t);
+ * }
+ * @endcode
+ */
+void parcObject_Display(const PARCObject *object, const int indentation);
+
+/**
+ * Get the `PARCObjectDescriptor` of the given `PARCObject`.
+ *
+ * @param [in] object A pointer to a valid `PARCObject` instance
+ *
+ * @return A pointer to the given PARCObject's `PARCObjectDescriptor`.
+ *
+ * Example:
+ * @code
+ * {
+ * struct MyType *t = parcObject_Create(sizeof(struct MyType), &MyType_Descriptor);
+ *
+ * PARCObjectDescriptor *descriptor = parcObject_GetDescriptor(t);
+ *
+ * parcObject_Release(&t);
+ * }
+ * @endcode
+ */
+const PARCObjectDescriptor *parcObject_GetDescriptor(const PARCObject *object);
+
+/**
+ * Set the `PARCObjectDescriptor` of the given `PARCObject`.
+ *
+ * @param [in] object A pointer to a valid `PARCObject` instance
+ * @param [in] objectType A pointer to a valid `PARCObjectDescriptor` instance
+ *
+ * @return The previous value of the given PARCObject's `PARCObjectDescriptor`.
+ */
+const PARCObjectDescriptor *parcObject_SetDescriptor(PARCObject *object, const PARCObjectDescriptor *objectType);
+
+/**
+ * @def parcObject_MetaInitialize
+ * @deprecated Use parcObject_Override instead;
+ *
+ * Initialize a PARCObjectDescriptor structure. Every function pointer is set to NULL.
+ *
+ * @param [in] objectType A pointer to the PARCObjectDescriptor structure to initialize.
+ *
+ * @return The pointer to the initialized PARCObjectDescriptor.
+ */
+#define parcObject_MetaInitialize(objectType) \
+ (objectType)->destructor = NULL, \
+ (objectType)->destroy = NULL, \
+ (objectType)->release = NULL, \
+ (objectType)->copy = NULL, \
+ (objectType)->toString = NULL, \
+ (objectType)->equals = NULL, \
+ (objectType)->compare = NULL, \
+ (objectType)->hashCode = NULL, \
+ (objectType)->toJSON = NULL, \
+ (objectType)->display = NULL, \
+ (objectType)->super = NULL
+
+
+/**
+ * Create new `PARCObjectDescriptor` based on an existing `PARCObjectDescriptor.`
+ * The new `PARCObjectDescriptor` uses the existing `PARCObjectDescriptor` as the super-type of the new descriptor.
+ */
+#define parcObject_Extends(_subtype, _superType, ...) \
+ LongBowCompiler_IgnoreInitializerOverrides \
+ parcObjectDescriptor_Declaration(_subtype) = { \
+ .super = &parcObject_DescriptorName(_superType), \
+ .name = #_subtype, \
+ .objectSize = 0, \
+ .objectAlignment = 0, \
+ .destroy = NULL, \
+ .destructor = NULL, \
+ .release = NULL, \
+ .copy = NULL, \
+ .toString = NULL, \
+ .equals = NULL, \
+ .compare = NULL, \
+ .hashCode = NULL, \
+ .toJSON = NULL, \
+ .display = NULL, \
+ .isLockable = true, \
+ .typeState = NULL, \
+ __VA_ARGS__ \
+ }; \
+ LongBowCompiler_WarnInitializerOverrides \
+ const PARCObjectDescriptor parcObject_DescriptorName(_subtype)
+
+/**
+ * Define a new PARC Object implementation, by composing a new PARC Object Descriptor referencing an old one.
+ * The new PARC Object implementation must be accompanied by the corresponding `typedef` of the type containing the object's data.
+ */
+#define parcObject_Override(_subtype, _superType, ...) \
+ parcObject_Extends(_subtype, _superType, \
+ .objectSize = sizeof(_subtype), \
+ .objectAlignment = sizeof(void *), \
+ __VA_ARGS__)
+
+
+/// Helper MACROS for PARCObject Normalization
+/** \cond */
+/**
+ * parcObject_DestroyWrapper builds the boiler plate wrapper for PARCObject type conversion in the
+ * destroy operation. Intended for internal use.
+ */
+#define parcObject_DestroyWrapper(_type, _fname) \
+ static void _autowrap_destroy_ ## _type(PARCObject **object) \
+ { \
+ _fname((_type **) object); \
+ }
+
+/**
+ * parcObject_DestructorWrapper builds the boiler plate wrapper for PARCObject type conversion in the
+ * destroy operation. Intended for internal use.
+ */
+#define parcObject_DestructorWrapper(_type, _fname) \
+ static bool _autowrap_destructor_ ## _type(PARCObject **object) \
+ { \
+ return _fname((_type **) object); \
+ }
+
+/**
+ * `parcObject_CopyWrapper` builds the boiler plate wrapper for PARCObject type conversion in the
+ * copy operation. Intended for internal use.
+ */
+#define parcObject_CopyWrapper(_type, _fname) \
+ static PARCObject *_autowrap_copy_ ## _type(const PARCObject *object) \
+ { \
+ return (PARCObject *) _fname((const _type *) object); \
+ }
+
+/**
+ * parcObject_ToStringWrapper builds the boiler plate wrapper for PARCObject type conversion in the
+ * ToString operation. Intended for internal use.
+ */
+#define parcObject_ToStringWrapper(_type, _fname) \
+ static char *_autowrap_toString_ ## _type(const PARCObject *object) \
+ { \
+ return _fname((const _type *) object); \
+ }
+
+/**
+ * `parcObject_EqualsWrapper` builds the boiler plate wrapper for PARCObject type conversion in the
+ * equals operation. Intended for internal use.
+ */
+#define parcObject_EqualsWrapper(_type, _fname) \
+ static bool _autowrap_equals_ ## _type(const PARCObject *a, const PARCObject *b) \
+ { \
+ return _fname((const _type *) a, (const _type *) b); \
+ }
+
+/**
+ * parcObject_CompareWrapper builds the boiler plate wrapper for PARCObject type conversion in the
+ * compare operation. Intended for internal use.
+ */
+#define parcObject_CompareWrapper(_type, _fname) \
+ static int _autowrap_compare_ ## _type(const PARCObject *a, const PARCObject *b) \
+ { \
+ return _fname((const _type *) a, (const _type *) b); \
+ }
+
+/**
+ * `parcObject_HashCodeWrapper` builds the boiler plate wrapper for PARCObject type conversion in the
+ * HashCode operation. Intended for internal use.
+ */
+#define parcObject_HashCodeWrapper(_type, _fname) \
+ static PARCHashCode _autowrap_hashCode_ ## _type(const PARCObject *object) \
+ { \
+ return _fname((const _type *) object); \
+ }
+
+/**
+ * `parcObject_CopyWrapper` builds the boiler plate wrapper for PARCObject type conversion in the
+ * ToJSON operation. Intended for internal use.
+ */
+#define parcObject_ToJSONWrapper(_type, _fname) \
+ static PARCJSON *_autowrap_toJSON_ ## _type(const PARCObject *object) \
+ { \
+ return _fname((const _type *) object); \
+ }
+
+/**
+ * `parcObject_DisplayWrapper` builds the boiler plate wrapper for PARCObject type conversion in the
+ * Display operation. Intended for internal use.
+ */
+#define parcObject_DisplayWrapper(_type, _fname) \
+ static void _autowrap_Display_ ## _type(const PARCObject *object, const int indentation) \
+ { \
+ _fname((const _type *) object, indentation); \
+ }
+
+/**
+ * _autowrap_NULL is a part of the c-macro trick for implement a macro If-Else switch.
+ * If included as a macro parameter it inserts a comma into the parameter list for that macro.
+ * This can be used by a switching macro that always resolves to the nth element and the
+ * presence of a comma generating macro changes which element is the nth. When NULL is used
+ * as a parameter in a call to "ExtendPARCObject", _autowrap_NULL will be the name generated which
+ * expands to a comma.
+ */
+#define _autowrap_NULL(...) ,
+
+/** \endcond */
+
+
+/**
+ * @define parcObject_ExtendPARCObject
+ * @deprecated Use parcObject_Override instead;
+ *
+ * @discussion parcObject_ExtendPARCObject is a helper macro for constructing a PARCObjectDescriptor Structure of
+ * function pointers pointing to a subtype's overriding functions. This struct serves the same
+ * purpose as a vTable in c++ and provides for simple polymorphism. The functions used as parameters
+ * should NOT call through to the parcObject function they override as this will result in an infinite loop.
+ * NULL should be used for functions where PARCObject's default implementation is desired.
+ *
+ * Note: It uses the parcCMacro_IfElse trickery to handle NULL parameters.
+ *
+ * @param [in] _destroy A pointer to the Destroy callback function.
+ * @param [in] _copy A pointer to the Copy callback function.
+ * @param [in] _toString A pointer to the ToString callback function.
+ * @param [in] _equals A pointer to the Equals callback function.
+ * @param [in] _compare A pointer to the Compare callback function.
+ * @param [in] _hashCode A pointer to the HashCode callback function.
+ * @param [in] _toJSON A pointer to the ToJSON callback function.
+ */
+#define parcObject_ExtendPARCObject(_type, _destroy, _copy, _toString, _equals, _compare, _hashCode, _toJSON) \
+ parcCMacro_IfElse(, parcObject_DestroyWrapper(_type, _destroy), _autowrap_ ## _destroy()) \
+ parcCMacro_IfElse(, parcObject_CopyWrapper(_type, _copy), _autowrap_ ## _copy()) \
+ parcCMacro_IfElse(, parcObject_ToStringWrapper(_type, _toString), _autowrap_ ## _toString()) \
+ parcCMacro_IfElse(, parcObject_EqualsWrapper(_type, _equals), _autowrap_ ## _equals()) \
+ parcCMacro_IfElse(, parcObject_CompareWrapper(_type, _compare), _autowrap_ ## _compare()) \
+ parcCMacro_IfElse(, parcObject_HashCodeWrapper(_type, _hashCode), _autowrap_ ## _hashCode()) \
+ parcCMacro_IfElse(, parcObject_ToJSONWrapper(_type, _toJSON), _autowrap_ ## _toJSON()) \
+ parcObject_Override(_type, PARCObject, \
+ .destroy = parcCMacro_IfElse(NULL, _autowrap_destroy_ ## _type, _autowrap_ ## _destroy()), \
+ .destructor = NULL, \
+ .release = NULL, \
+ .copy = parcCMacro_IfElse(NULL, _autowrap_copy_ ## _type, _autowrap_ ## _copy()), \
+ .toString = parcCMacro_IfElse(NULL, _autowrap_toString_ ## _type, _autowrap_ ## _toString()), \
+ .equals = parcCMacro_IfElse(NULL, _autowrap_equals_ ## _type, _autowrap_ ## _equals()), \
+ .compare = parcCMacro_IfElse(NULL, _autowrap_compare_ ## _type, _autowrap_ ## _compare()), \
+ .hashCode = parcCMacro_IfElse(NULL, _autowrap_hashCode_ ## _type, _autowrap_ ## _hashCode()), \
+ .toJSON = parcCMacro_IfElse(NULL, _autowrap_toJSON_ ## _type, _autowrap_ ## _toJSON()), \
+ .display = NULL)
+
+/**
+ * @define parcObject_CreateInstance
+ *
+ * `parcObject_CreateInstance` is a helper C-macro that creates an instance of a PARCObject subtype
+ * using `parcObject_CreateInstanceImpl` that is based on the PARCObjectDescriptor.
+ *
+ * @param [in] _subtype A subtype's type string (e.g. PARCBuffer)
+ */
+#define parcObject_CreateInstance(_subtype) \
+ parcObject_CreateInstanceImpl(&parcObject_DescriptorName(_subtype))
+
+PARCObject *parcObject_CreateInstanceImpl(const PARCObjectDescriptor *descriptor);
+
+/**
+ * @define parcObject_CreateAndClearInstance
+ *
+ * parcObject_CreateAndClearInstance is a helper C-macro that creates an instance of a PARCObject subtype
+ * using parcObject_CreateAndClear that is based on the PARCObjectDescriptor struct created by the
+ * parcObject_ExtendPARCObject macro.
+ *
+ * @param [in] _subtype A subtype's type string (e.g. PARCBuffer)
+ */
+#define parcObject_CreateAndClearInstance(_subtype) \
+ (_subtype *) parcObject_CreateAndClearInstanceImpl(&parcObject_DescriptorName(_subtype))
+
+/**
+ * Create a reference counted segment of memory of at least @p objectLength long.
+ *
+ * The implementation pointer, is either NULL or points to a valid `PARCObjectDescriptor` structure
+ * containing the callback functions that implement the object's life-cycle operations.
+ *
+ * The allocated memory is such that the memory's base address is aligned on a sizeof(void *) boundary,
+ * and filled with zero bytes.
+ *
+ * If memory cannot be allocated, `errno` is set to ENOMEM.
+ *
+ * @param [in] descriptor A pointer to a valid `PARCObjectDescriptor` structure.
+ *
+ * @return NULL The memory could not be allocated.
+ * @return non-NULL A pointer to reference counted memory of at least length bytes.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval *t = parcObject_CreateAndClearInstanceImpl(sizeof(struct timeval), &PARCObject_Descriptor);
+ * }
+ * @endcode
+ *
+ * @see PARCObjectDescriptor
+ * @see parcObject_Create
+ */
+PARCObject *parcObject_CreateAndClearInstanceImpl(const PARCObjectDescriptor *descriptor);
+
+/**
+ * Define a static PARCObject instance for the given type, alignment, per-object data.
+ *
+ * Once the instance has been defined, it must be initialised via `parcObject_InitInstance`
+ * or `parcObject_InitAndClearInstance` before it is used.
+ *
+ * @return A pointer to an invalid `PARCObject` instance that must be initialised .
+ */
+#define parcObject_Instance(_type_, _alignment_, _size_) \
+ (_type_ *) (& (char[parcObject_TotalSize(_alignment_, _size_)]) { 0 }[parcObject_PrefixLength(sizeof(void *))])
+
+/**
+ * @define parcObject_InitInstance
+ *
+ * `parcObject_InitInstance` is a helper C-macro that initializes a portion of memory to contain a `PARCObject` subtype
+ * using `parcObject_InitInstanceImpl`.
+ *
+ * @param [in] _object_ A pointer to memory that will contain the object and its meta-data.
+ * @param [in] _subtype A subtype's type name.
+ */
+#define parcObject_InitInstance(_object_, _subtype) \
+ parcObject_InitInstanceImpl(_object_, &parcObject_DescriptorName(_subtype))
+
+/**
+ * @define parcObject_InitInstanceImpl
+ *
+ * Initialize a PARCObject instance given the `PARCObjectDescriptor`.
+ * Any previous state of the given PARCObject is destroyed.
+ *
+ * @param [in] object A pointer to an existing valid or invalid `PARCObject` instance.
+ * @param [in] descriptor A pointer to a valid `PARCObjectDescriptor` structure.
+ */
+PARCObject *parcObject_InitInstanceImpl(PARCObject *object, const PARCObjectDescriptor *descriptor);
+
+/**
+ * @define parcObject_InitAndClearInstance
+ *
+ * `parcObject_InitAndClearInstance` is a helper C-macro that initializes a portion of memory to contain a PARCObject subtype
+ * using `parcObject_InitAndClearInstanceImpl`.
+ *
+ * @param [in] _object_ A pointer to memory that will contain the object and its meta-data.
+ * @param [in] _subtype A subtype's type name.
+ */
+#define parcObject_InitAndClearInstance(_object_, _subtype) \
+ parcObject_InitAndClearInstanceImpl(_object_, &parcObject_DescriptorName(_subtype))
+
+/**
+ * Create a reference counted segment of memory of at least @p objectLength long.
+ *
+ * The implementation pointer, is either NULL or points to a valid `PARCObjectDescriptor` structure
+ * containing the callback functions that implement the object's life-cycle operations.
+ *
+ * The allocated memory is such that the memory's base address is aligned on a sizeof(void *) boundary,
+ * and filled with zero bytes.
+ *
+ * If memory cannot be allocated, `errno` is set to `ENOMEM`.
+ *
+ * @param [in] object A pointer to an existing valid or invalid `PARCObject` instance.
+ * @param [in] descriptor A pointer to a valid `PARCObjectDescriptor` structure.
+ *
+ * @return NULL The memory could not be allocated.
+ * @return non-NULL A pointer to reference counted memory of at least length bytes.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * }
+ * @endcode
+ *
+ * @see PARCObjectDescriptor
+ * @see parcObject_Create
+ */
+PARCObject *parcObject_InitAndClearInstanceImpl(PARCObject *object, const PARCObjectDescriptor *descriptor);
+
+/**
+ * Compute the number of bytes necessary for a PARC Object prefix.
+ *
+ * The @p _alignment_ parameter specifies the required memory alignment of the object.
+ *
+ * @param [in] _alignment_ An unsigned integer value greater than `sizeof(void *)`
+ *
+ * @return The number of bytes necessary for a PARC Object header.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+// The constant value here must be greater than or equal to the size of the internal _PARCObjectHeader structure.
+#define parcObject_PrefixLength(_alignment_) ((152 + (_alignment_ - 1)) & - _alignment_)
+
+/**
+ * Compute the number of bytes necessary for a PARC Object.
+ *
+ * The number of bytes consists of the number of bytes for the PARC Object header, padding, and the object's specific data.
+ *
+ * The @p _alignment_ parameter specifies the required memory alignment of the object.
+ * The @p _size_ parameter specifies the number of bytes necessary for the object specific data.
+ */
+#define parcObject_TotalSize(_alignment_, _size_) (parcObject_PrefixLength(_alignment_) + _size_)
+
+/**
+ * Wrap a static, unallocated region of memory producing a valid pointer to a `PARCObject` instance.
+ *
+ * Note that the return value will not be equal to the value of @p origin.
+ *
+ * @param [in] memory A pointer to memory that will contain the object and its state.
+ * @param [in] descriptor The subtype name that will be used to compose the name of the `PARCObjectDescriptor` for the object.
+ *
+ * @return NULL An error occured.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+#define parcObject_Wrap(_memory_, _subtype) \
+ parcObject_WrapImpl(_memory_, &parcObject_DescriptorName(_subtype))
+
+/**
+ * Wrap a static, unallocated region of memory producing a valid pointer to a `PARCObject` instance.
+ *
+ * Note that the return value will not be equal to the value of @p origin.
+ *
+ * @param [in] memory A pointer to memory that will contain the object and its state.
+ * @param [in] descriptor A pointer to a valid `PARCObjectDescriptor` for the object.
+ *
+ * @return NULL An error occured.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCObject *parcObject_WrapImpl(void *memory, const PARCObjectDescriptor *descriptor);
+
+/**
+ * @def parcObject_ImplementAcquire
+ *
+ * `parcObject_ImplementAcquire` is a helper C-macro that creates a canonical subtype specific
+ * Acquire function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. parcBuffer)
+ * @param [in] _type A subtype's type string (e.g. PARCBuffer)
+ */
+#define parcObject_ImplementAcquire(_namespace, _type) \
+ _type * _namespace ## _Acquire(const _type * pObject) { \
+ return (_type *) parcObject_Acquire((PARCObject *) pObject); \
+ } extern _type *_namespace ## _Acquire(const _type * pObject)
+
+/**
+ * @def parcObject_ImplementRelease
+ *
+ * `parcObject_ImplementRelease` is a helper C-macro that creates a canonical subtype specific
+ * Release function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. parcBuffer)
+ * @param [in] _type A subtype's type string (e.g. PARCBuffer)
+ */
+#define parcObject_ImplementRelease(_namespace, _type) \
+ inline void _namespace ## _Release(_type **pObject) { \
+ parcObject_Release((PARCObject **) pObject); \
+ } extern void _namespace ## _Release(_type **pObject)
+
+/**
+ * `parcObject_ImplementationCheck` is a helper macro that will generate compile time warnings for
+ * missing canonical functions or canonical functions with faulty signatures.
+ *
+ * @param _namespace A subtype's namespace string (e.g. parcBuffer)
+ * @param _type A subtype's type string (e.g. PARCBuffer)
+ */
+#define parcObject_ImplementationCheck(_namespace, _type) \
+ static void \
+ _impl_check() { \
+ _type *po; \
+ const _type co; \
+ const _type *pco; \
+ pco = _namespace ## _Copy(&co); \
+ pco = _namespace ## _Acquire(&co); \
+ pco = pco; \
+ _namespace ## _Release(&po); \
+ bool b = _namespace ## _Equals(&co, &co); \
+ b = b; \
+ int i = _namespace ## _Compare(&co, &co); \
+ i = i; \
+ char *pc = _namespace ## _ToString(&co); \
+ pc = pc; \
+ uint32_t ui = _namespace ## _HashCode(&co); \
+ ui = ui; \
+ PARCJSON *pj = _namespace ## _ToJSON(&co); \
+ pj = pj; \
+ } typedef void parcCMacro_Cat (_type, _IC_NOOP)
+
+/**
+ * Obtain the lock on the given `PARCObject` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] object A pointer to a valid `PARCObject` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, the `PARCObject` is invalid, or does not support locking.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcObject_Lock(object)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+bool parcObject_Lock(const PARCObject *object);
+
+/**
+ * @def parcObject_ImplementLock
+ *
+ * `parcObject_ImplementLock` is a helper C-macro that defines a static, inline facade for the `parcObject_Lock` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type string (e.g. `PARCBuffer`)
+ */
+#define parcObject_ImplementLock(_namespace, _type) \
+ static inline bool _namespace ## _Lock(const _type * pObject) { \
+ return parcObject_Lock((PARCObject *) pObject); \
+ } typedef void parcCMacro_Cat (_type, _Lock_NOOP)
+
+/**
+ * Try to obtain the advisory lock on the given `PARCObject` instance.
+ *
+ * Once the lock is obtained, the caller must release the lock via `parcObject_Unlock`.
+ *
+ * @param [in] object A pointer to a valid `PARCObject` instance.
+ *
+ * @return true The `PARCObject` is locked.
+ * @return false The `PARCObject` is unlocked, or does not support locking.
+ *
+ * Example:
+ * @code
+ * {
+ * while (parcObject_TryLock(object))
+ * ;
+ * }
+ * @endcode
+ */
+bool parcObject_TryLock(const PARCObject *object);
+
+/**
+ * @def parcObject_ImplementTryLock
+ *
+ * `parcObject_ImplementTryLock` is a helper C-macro that defines a static, inline facade for the `parcObject_TryLock` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type string (e.g. `PARCBuffer`)
+ */
+#define parcObject_ImplementTryLock(_namespace, _type) \
+ static inline bool _namespace ## _TryLock(const _type * pObject) { \
+ return parcObject_TryLock((PARCObject *) pObject); \
+ } typedef void parcCMacro_Cat (_type, _TryLock_NOOP)
+
+/**
+ * Try to unlock the advisory lock on the given `PARCObject` instance.
+ *
+ * @param [in] object A pointer to a valid `PARCObject` instance.
+ *
+ * @return true The `PARCObject` was locked and now is unlocked.
+ * @return false The `PARCObject` was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcObject_Lock(Object)) {
+ * parcObject_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+bool parcObject_Unlock(const PARCObject *object);
+
+/**
+ * @def parcObject_ImplementUnlock
+ *
+ * `parcObject_ImplementUnlock` is a helper C-macro that defines a static, inline facade for the `parcObject_Unlock` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type string (e.g. `PARCBuffer`)
+ */
+#define parcObject_ImplementUnlock(_namespace, _type) \
+ static inline bool _namespace ## _Unlock(const _type * pObject) { \
+ return parcObject_Unlock((PARCObject *) pObject); \
+ } typedef void parcCMacro_Cat (_type, _Unlock_NOOP)
+
+/**
+ * Determine if the advisory lock on the given PARCObject instance is locked.
+ *
+ * @param [in] object A pointer to a valid PARCObject instance.
+ *
+ * @return true The `PARCObject` is locked.
+ * @return false The `PARCObject` is unlocked.
+ * Example:
+ * @code
+ * {
+ * if (parcObject_Lock(object)) {
+ * ...
+ * if (parcObject_IsLocked(object) {
+ * ....
+ * }
+ * ...
+ * parcObject_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+bool parcObject_IsLocked(const PARCObject *object);
+
+/**
+ * @def parcObject_ImplementIsLocked
+ *
+ * parcObject_ImplementIsLocked is a helper C-macro that defines a static, inline facade for the `parcObject_IsLocked` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type string (e.g. `PARCBuffer`)
+ */
+#define parcObject_ImplementIsLocked(_namespace, _type) \
+ static inline bool _namespace ## _IsLocked(const _type * pObject) { \
+ return parcObject_IsLocked((const PARCObject *) pObject); \
+ } typedef void parcCMacro_Cat (_type, _IsLocked_NOOP)
+
+/**
+ * Causes the calling thread to wait until another thread invokes the `parcObject_Notify()` function on the same object.
+ *
+ * The calling thread must own this object's lock.
+ * The calling thread will release ownership of this lock and wait until another thread invokes `parcObject_Notify`
+ * on the same object. The original calling thread then re-obtains ownership of the lock and resumes execution.
+ *
+ * This function must only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid PARCObject instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcObject_Lock(object)) {
+ * ...
+ * if (parcObject_Wait(object) {
+ * ....
+ * }
+ * ...
+ * parcObject_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+void parcObject_Wait(const PARCObject *object);
+
+/**
+ * @def parcObject_ImplementWait
+ *
+ * parcObject_ImplementWait is a helper C-macro that defines a static, inline facade for the `parcObject_Wait` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type string (e.g. `PARCBuffer`)
+ * @see parcObject_Wait
+ */
+#define parcObject_ImplementWait(_namespace, _type) \
+ static inline void _namespace ## _Wait(const _type * pObject) { \
+ parcObject_Wait((const PARCObject *) pObject); \
+ } typedef void parcCMacro_Cat (_type, _Wait_NOOP)
+
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the `parcObject_Notify()`
+ * function on the same object or the system time equals or exceeds the specified time.
+ *
+ * The calling thread must own the object's lock.
+ * The calling thread will release ownership of this lock and wait until another thread invokes
+ * `parcObject_Notify` or the computer's system time equals or exceeds that specified by @p time.
+ * on the same object.
+ * The original calling thread then re-obtains ownership of the lock and resumes execution.
+ *
+ * This function must only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid PARCObject instance.
+ *
+ * @returns false if the alloted time was exceeded.
+ * @returns true if another thread invoked the `parcObject_Notify()` function
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval tv;
+ * gettimeofday(&tv, NULL);
+ *
+ * struct timespec absoluteTime;
+ * absoluteTime.tv_sec = tv.tv_sec + 0;
+ * absoluteTime.tv_nsec = 0;
+ *
+ * parcObject_WaitUntil(object, &absoluteTime);
+ * }
+ * @endcode
+ */
+bool parcObject_WaitUntil(const PARCObject *object, const struct timespec *time);
+
+/**
+ * @def parcObject_ImplementWaitUntil
+ *
+ * parcObject_ImplementWaitUntil is a helper C-macro that defines a static, inline facade for the
+ * `parcObject_WaitUntil` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type string (e.g. `PARCBuffer`)
+ * @see parcObject_WaitUntil
+ */
+#define parcObject_ImplementWaitUntil(_namespace, _type) \
+ static inline bool _namespace ## _WaitUntil(const _type * pObject, const struct timespec *time) { \
+ return parcObject_WaitUntil((const PARCObject *) pObject, time); \
+ } typedef void parcCMacro_Cat (_type, _WaitUntil_NOOP)
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the `parcObject_Notify()`
+ * function on the same object or the given number of nanoseconds elapses.
+ *
+ * The calling thread must own the object's lock.
+ *
+ * The calling thread will release ownership of its lock and wait until another thread invokes
+ * `parcObject_Notify` on the same object,
+ * or the computer's system time equals or exceeds the time specified by the
+ * time of invocation plus nanoSeconds.
+ * The original calling thread then re-obtains ownership of the lock and resumes execution.
+ *
+ * This function must only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid PARCObject instance.
+ * @param [in] nanoSeconds The number of nanoseconds to wait.
+ *
+ * @returns false if the allotted time was exceeded.
+ * @returns true if another thread invoked the `parcObject_Notify()` function
+ *
+ * Example:
+ * @code
+ * {
+ * parcObject_WaitFor(object, 1000000000UL);
+ * }
+ * @endcode
+ */
+bool parcObject_WaitFor(const PARCObject *object, const uint64_t nanoSeconds);
+
+/**
+ * @def parcObject_ImplementWaitUntil
+ *
+ * parcObject_ImplementWaitUntil is a helper C-macro that defines a static, inline facade for the
+ * `parcObject_WaitUntil` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type string (e.g. `PARCBuffer`)
+ * @see parcObject_WaitUntil
+ */
+#define parcObject_ImplementWaitFor(_namespace, _type) \
+ static inline bool _namespace ## _WaitFor(const _type * pObject, const unsigned long nanoSeconds) { \
+ return parcObject_WaitFor((const PARCObject *) pObject, nanoSeconds); \
+ } typedef void parcCMacro_Cat (_type, _WaitFor_NOOP)
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcObject_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example,
+ * the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] object A pointer to a valid `PARCObject` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcObject_Lock(object)) {
+ * parcObject_Notify(object);
+ * parcObject_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+void parcObject_Notify(const PARCObject *object);
+
+/**
+ * @def parcObject_ImplementNotify
+ *
+ * parcObject_ImplementNotify is a helper C-macro that defines a static, inline facade for the `parcObject_Notify` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type string (e.g. `PARCBuffer`)
+ */
+#define parcObject_ImplementNotify(_namespace, _type) \
+ static inline void _namespace ## _Notify(const _type * pObject) { \
+ parcObject_Notify((const PARCObject *) pObject); \
+ } typedef void parcCMacro_Cat (_type, _Notify_NOOP)
+
+
+/**
+ * Wakes up all threads that are waiting on the given object's lock.
+ *
+ * A thread waits on an object by calling one of the wait methods, `parcObject_Wait`, `parcObject_WaitFor`, `parcObject_WaitUntil`.
+ * The awakened threads will proceed after the current thread relinquishes the lock on the given object.
+ * The awakened threads will compete in the usual manner with any other threads that might be actively competing
+ * to synchronize on this object.
+ * Awakened threads have no priority between them in being the next thread to lock this object.
+ *
+ * This method can only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid `PARCObject` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcObject_Lock(object)) {
+ * parcObject_NotifyAll(object);
+ * parcObject_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+void parcObject_NotifyAll(const PARCObject *object);
+
+/**
+ * @def parcObject_ImplementNotifyAll
+ *
+ * parcObject_ImplementNotifyAll is a helper C-macro that defines a static, inline facade for the `parcObject_NotifyAll` function.
+ *
+ * @param [in] _namespace A subtype's namespace string (e.g. `parcBuffer`)
+ * @param [in] _type A subtype's type (e.g. `PARCBuffer`)
+ */
+#define parcObject_ImplementNotifyAll(_namespace, _type) \
+ static inline void _namespace ## _NotifyAll(const _type * pObject) { \
+ parcObject_NotifyAll((const PARCObject *) pObject); \
+ } typedef void parcCMacro_Cat (_type, _NotifyAll_NOOP)
+
+/**
+ * @def parcObject_Mutex
+ *
+ * This macro uses the functions `parcObject_Lock` and `parcObject_Unlock`
+ * to provide a simple syntax for implementing a mutual exclusion region of code.
+ *
+ * @param [in] _object_ A pointer to a valid PARCObject that implements locking.
+ *
+ * Example:
+ * @code
+ * {
+ * parcObject_Mutex(object) {
+ * ....
+ * }
+ * }
+ * @endcode
+ * @see parcObject_Synchronize
+ */
+#define parcObject_Mutex(_object_) for (bool once = true; once && parcObject_Lock(_object_); parcObject_Unlock(_object_), once = false)
+
+/**
+ * Determine if a given `PARCObject` is and instance of the specified `PARCObjectDescriptor`.
+ *
+ * @param [in] object A pointer to a valid PARCObject instance.
+ * @param [in] descriptor A pointer to a valid PARCObjectDescriptor instance.
+ *
+ * @return true @p object is an instance of @p descriptor.
+ * @return false @p object is not an instance of @p descriptor.
+ */
+bool parcObject_IsInstanceOf(const PARCObject *object, const PARCObjectDescriptor *descriptor);
+
+/**
+ * Atomically set an object's barrier.
+ *
+ * If the barrier is not set, the barrier will be set and this function returns `true`.
+ *
+ * If the barrier is already set, any subsequent attempt to set the barrier will block until the barrier is unset
+ * (see `parcObject_BarrierUnset`).
+ * If there are multiple competitors to set the barrier,
+ * only one will (indiscriminately) succeed and return and the remaining will continue to attempt to set the barrier.
+ *
+ * Barriers can be used in both threaded and non-threaded applications,
+ * but are not a substitute for thread locking and do not interoperate the wait and notify operations.
+ *
+ * Barriers should be used in pairs within the same level of program abstraction to avoid confusion.
+ * It is possible to set a barrier without ever unsetting the same barrier,
+ * and as a consequence any other attempt to set the same barrier will hang the program.
+ *
+ * @param [in] object A pointer to a valid PARCObject
+ *
+ * @return true
+ *
+ * Example:
+ * @code
+ * {
+ * parcObject_BarrierSet(object);
+ *
+ * ...
+ *
+ * parcObject_BarrierUnset(object);
+ * }
+ * @endcode
+ * @see parcObject_BarrierUnset
+ * @see parcObject_Synchronize
+ */
+bool parcObject_BarrierSet(const PARCObject *object);
+
+/**
+ * Unset an objects' barrier.
+ *
+ * If a barrier is set (see `parcObject_BarrierSet`), the barrier is unset (see `parcObject_BarrierUnset`).
+ *
+ * If a barrier is not set, this function will block until the barrier is set,
+ * whereupon it will be immediately unset the barrier and return.
+ *
+ * If there are multiple competitors attempting to unset the barrier,
+ * only one will (indiscriminately) succeed and return and the remaining will continue to attempt to unset the barrier.
+ *
+ * Barriers are not a substitute for thread locking and do not interoperate the wait and notify operations.
+ *
+ *
+ * @param [in] object A pointer to a valid `PARCObject`
+ *
+ * @return false
+ *
+ * Example:
+ * @code
+ * {
+ * parcObject_BarrierSet(object);
+ *
+ * ...
+ *
+ * parcObject_BarrierUnset(object);
+ * }
+ * @endcode
+ */
+bool parcObject_BarrierUnset(const PARCObject *object);
+
+/**
+ * Synchronize on a `PARCObject` instance to provide a simple mutual exclusion region of code.
+ *
+ * This macro uses the functions `parcObject_BarrierSet` and `parcObject_BarrierUnset`
+ * to provide a simple syntax for implementing a mutual exclusion region of code.
+ *
+ * This defines and uses the local variable `_parcObjectSynchronize` which will always appear to be true to the calling function
+ * and must never be defined by the calling function, or any module.
+ *
+ * @param [in] object A pointer to a valid `PARCObject`
+ *
+ * Example:
+ * @code
+ * {
+ * parcObject_Synchronize(_object_) {
+ * // Only one thread executes this code at a single time.
+ * }
+ * }
+ * @endcode
+ * @see parcObject_Mutex
+ */
+#define parcObject_Synchronize(_object_) for (bool _parcObjectSynchronize = parcObject_BarrierSet(_object_); _parcObjectSynchronize; _parcObjectSynchronize = parcObject_BarrierUnset(_object_))
+
+#endif // libparc_parc_Object_h
diff --git a/libparc/parc/algol/parc_OldSortedList.c b/libparc/parc/algol/parc_OldSortedList.c
new file mode 100755
index 00000000..ef007388
--- /dev/null
+++ b/libparc/parc/algol/parc_OldSortedList.c
@@ -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 <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_SortedList.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+
+struct parc_sorted_list {
+ parcSortedList_Compare compare;
+ PARCArrayList *arrayList;
+};
+
+PARCSortedList *
+parcSortedList_Create(parcSortedList_Compare compareFunction)
+{
+ PARCSortedList *sortedList = parcMemory_Allocate(sizeof(PARCSortedList));
+ assertNotNull(sortedList, "parcMemory_Allocate(%zu) returned NULL", sizeof(PARCSortedList));
+ sortedList->arrayList = parcArrayList_Create(NULL);
+ sortedList->compare = compareFunction;
+ return sortedList;
+}
+
+void
+parcSortedList_Destroy(PARCSortedList **parcSortedListPointer)
+{
+ parcArrayList_Destroy(&((*parcSortedListPointer)->arrayList));
+ parcMemory_Deallocate((void **) parcSortedListPointer);
+ *parcSortedListPointer = NULL;
+}
+
+void
+parcSortedList_Add(PARCSortedList *parcSortedList, void *newItem)
+{
+ assertNotNull(parcSortedList, "sortedList parameter can't be null");
+ assertNotNull(parcSortedList->arrayList, "arrayList can't be null");
+ assertNotNull(newItem, "newItem can't be null");
+
+ size_t total_items = parcArrayList_Size(parcSortedList->arrayList);
+ for (size_t i = 0; i < total_items; i++) {
+ void *oldItem = parcArrayList_Get(parcSortedList->arrayList, i);
+ if (parcSortedList->compare(newItem, oldItem) == -1) {
+ // The old item at position i is bigger than the new item,
+ // we must insert the newItem here.
+ parcArrayList_InsertAtIndex(parcSortedList->arrayList, newItem, i);
+ return;
+ }
+ }
+ // We reached the end of the list, it must go here...
+ parcArrayList_Add(parcSortedList->arrayList, newItem);
+}
+
+size_t
+parcSortedList_Length(PARCSortedList *parcSortedList)
+{
+ return parcArrayList_Size(parcSortedList->arrayList);
+}
+
+void *
+parcSortedList_PopFirst(PARCSortedList *parcSortedList)
+{
+ assertNotNull(parcSortedList, "sortedList parameter can't be null");
+ assertNotNull(parcSortedList->arrayList, "arrayList can't be null");
+
+ if (parcArrayList_Size(parcSortedList->arrayList) == 0) {
+ return NULL;
+ }
+ void *item = parcArrayList_Get(parcSortedList->arrayList, 0);
+ parcArrayList_RemoveAndDestroyAtIndex(parcSortedList->arrayList, 0);
+ return item;
+}
+
+void *
+parcSortedList_GetFirst(PARCSortedList *parcSortedList)
+{
+ assertNotNull(parcSortedList, "sortedList parameter can't be null");
+ assertNotNull(parcSortedList->arrayList, "arrayList can't be null");
+
+ if (parcArrayList_Size(parcSortedList->arrayList) == 0) {
+ return NULL;
+ }
+ return parcArrayList_Get(parcSortedList->arrayList, 0);
+}
diff --git a/libparc/parc/algol/parc_OldSortedList.h b/libparc/parc/algol/parc_OldSortedList.h
new file mode 100755
index 00000000..2a00a0fa
--- /dev/null
+++ b/libparc/parc/algol/parc_OldSortedList.h
@@ -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.
+ */
+
+/**
+ * @file parc_SortedList.h
+ * @ingroup datastructures
+ * @brief A sorted list
+ *
+ */
+#ifndef libparc_parc_SortedList_h
+#define libparc_parc_SortedList_h
+
+#include <stdlib.h>
+
+struct parc_sorted_list;
+
+typedef struct parc_sorted_list PARCSortedList;
+
+/**
+ * This is a compare function that must be defined for the sorted list to sort
+ *
+ * @param [in] object1 The first object to compare.
+ * @param [in] object2 The second object to compare.
+ * @return -1 if object1 < object2, 0 if object1 == object2, 1 if object1 > object2.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef int (*parcSortedList_Compare)(const void *object1, const void *object2);
+
+/**
+ * Create a sorted list
+ * This list will be sorted from smallest to largest based on the compare function.
+ *
+ * @param [in] compareFunction A compare function to determine how elements are sorted.
+ * @return An allocated `PARCSortedList`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCSortedList *parcSortedList_Create(parcSortedList_Compare compareFunction);
+
+/**
+ * Destroy an allocated sorted list
+ *
+ * @param [in,out] parcSortedListPointer A pointer to the allocated sorted list to destroy. The pointer will be set to NULL.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcSortedList_Destroy(PARCSortedList **parcSortedListPointer);
+
+/**
+ * Add an element to the sorted list.
+ *
+ * @param [in,out] parcSortedList A pointer to the `PARCSortedList` to modify.
+ * @param newItem The new item to add to the list. This item must be comparable by the compare function.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcSortedList_Add(PARCSortedList *parcSortedList, void *newItem);
+
+/**
+ * Return the length of the list
+ *
+ * @param [in] parcSortedList a pointer to an allocated sorted list.
+ * @return return the length of the list, the number of elements.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcSortedList_Length(PARCSortedList *parcSortedList);
+
+/**
+ * Pop the first element on the sorted list. This will remove the element from the list and return it to the caller.
+ *
+ * @param [in,out] parcSortedList A pointer to the `PARCSortedList` to modify.
+ * @return The first element of @p parcSortedList.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcSortedList_PopFirst(PARCSortedList *parcSortedList);
+
+/**
+ * Get the first element on the sorted list. This will NOT remove the element from the list.
+ *
+ * @param [in] parcSortedList A pointer to the `PARCSortedList` .
+ * @return The first element of the sorted list.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcSortedList_GetFirst(PARCSortedList *parcSortedList);
+#endif // libparc_parc_SortedList_h
diff --git a/libparc/parc/algol/parc_OutputStream.c b/libparc/parc/algol/parc_OutputStream.c
new file mode 100755
index 00000000..d00c1f09
--- /dev/null
+++ b/libparc/parc/algol/parc_OutputStream.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 <stdio.h>
+#include <stdarg.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_OutputStream.h>
+
+struct parc_output_stream {
+ void *instance;
+ const PARCOutputStreamInterface *interface;
+};
+
+static void
+_destroy(PARCOutputStream **streamPtr)
+{
+ PARCOutputStream *stream = *streamPtr;
+ (stream->interface->Release)((PARCOutputStream **) &stream->instance);
+}
+
+parcObject_ExtendPARCObject(PARCOutputStream, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCOutputStream *
+parcOutputStream_Create(void *instance, const PARCOutputStreamInterface *interface)
+{
+ PARCOutputStream *result = parcObject_CreateInstance(PARCOutputStream);
+ result->instance = instance;
+ result->interface = interface;
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcOutputStream, PARCOutputStream);
+
+parcObject_ImplementRelease(parcOutputStream, PARCOutputStream);
+
+size_t
+parcOutputStream_Write(PARCOutputStream *stream, PARCBuffer *buffer)
+{
+ return (stream->interface->Write)(stream->instance, buffer);
+}
+
+size_t
+parcOutputStream_WriteCStrings(PARCOutputStream *stream, ...)
+{
+ va_list ap;
+ va_start(ap, stream);
+
+ size_t result = 0;
+
+ for (char *string = va_arg(ap, char *); string != NULL; string = va_arg(ap, char *)) {
+ result += parcOutputStream_WriteCString(stream, string);
+ }
+
+ return result;
+}
+
+size_t
+parcOutputStream_WriteCString(PARCOutputStream *stream, const char *string)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString((char *) string);
+ size_t result = (stream->interface->Write)(stream->instance, buffer);
+ parcBuffer_Release(&buffer);
+ return result;
+}
diff --git a/libparc/parc/algol/parc_OutputStream.h b/libparc/parc/algol/parc_OutputStream.h
new file mode 100755
index 00000000..db0ba343
--- /dev/null
+++ b/libparc/parc/algol/parc_OutputStream.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 parc_OutputStream.h
+ * @ingroup inputoutput
+ * @brief A polymophic interface to specific implementations of modules that implement the
+ * output stream capabilities.
+ *
+ *
+ *
+ */
+#ifndef libparc_parc_OutputStream_h
+#define libparc_parc_OutputStream_h
+
+#include <parc/algol/parc_Buffer.h>
+
+struct parc_output_stream;
+typedef struct parc_output_stream PARCOutputStream;
+
+typedef struct parc_output_stream_interface {
+ size_t (*Write)(PARCOutputStream *stream, PARCBuffer *buffer);
+
+ PARCOutputStream *(*Acquire)(PARCOutputStream * stream);
+
+ void (*Release)(PARCOutputStream **streamPtr);
+} PARCOutputStreamInterface;
+
+/**
+ * Create an valid PARCOutputStream instance from the given pointers to a properly
+ * initialized `PARCOutputStreamInterface`
+ * and specific instance structure that will be supplied to the underlying interface.
+ *
+ * @param [in] instance A pointer to a `PARCObject` that will be the parameter to the functions specifed by @p interface.
+ * @param [in] interface A pointer to a `PARCOutputStreamInterface`.
+ *
+ * @return non-NULL A pointer to a valid PARCOutputStream instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcOutputStream_Create(parcFileOutputStream_Acquire(fileOutputStream),
+ * PARCFileOutputStreamAsPARCInputStream);
+ * }
+ * @endcode
+ */
+PARCOutputStream *parcOutputStream_Create(void *instance, const PARCOutputStreamInterface *interface);
+
+/**
+ * Write the contents of the given `PARCBuffer` to the output stream.
+ *
+ * The position of the `PARCBuffer` will be set to its limit as a side-effect.
+ *
+ * @param [in] stream A pointer to a valid `PARCOutputStream` instance.
+ * @param [in] buffer A pointer to the `PARCBuffer` whose contents should be written to @p stream.
+ *
+ * @return The number of bytes written
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcOutputStream_Create(parcFileOutputStream_Acquire(fileOutputStream),
+ * PARCFileOutputStreamAsPARCInputStream);
+ * PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ * parcOutputStream_Write(output, buffer);
+ * parcOutputStream_Release(&output);
+ * }
+ * @endcode
+ */
+size_t parcOutputStream_Write(PARCOutputStream *stream, PARCBuffer *buffer);
+
+/**
+ * Write a nul-terminated C string to the given `PARCOutputStream`.
+ *
+ * @param [in] stream A pointer to a valid `PARCOutputStream` instance.
+ * @param [in] string A nul-terminated C string.
+ *
+ * @return The number of bytes written.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcOutputStream_Create(parcFileOutputStream_Acquire(fileOutputStream),
+ * PARCFileOutputStreamAsPARCInputStream);
+ *
+ * parcOutputStream_WriteCStrings(output, "Hello", " ", "World", NULL);
+ *
+ * parcOutputStream_Release(&output);
+ * }
+ * @endcode
+ */
+size_t parcOutputStream_WriteCString(PARCOutputStream *stream, const char *string);
+
+/**
+ * Write one or more nul-terminated C strings to the given `PARCOutputStream`.
+ *
+ * @param [in] stream A pointer to a valid `PARCOutputStream` instance.
+ * @param [in] ... A NULL terminated variable argument list of nul-terminated C strings.
+ *
+ * @return The number of bytes written.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcOutputStream_Create(parcFileOutputStream_Acquire(fileOutputStream),
+ * PARCFileOutputStreamAsPARCInputStream);
+ *
+ * parcOutputStream_WriteCStrings(output, "Hello", " ", "World", NULL);
+ *
+ * parcOutputStream_Release(&output);
+ * }
+ * @endcode
+ */
+size_t parcOutputStream_WriteCStrings(PARCOutputStream *stream, ...);
+
+/**
+ * Increase the number of references to a `PARCOutputStream`.
+ *
+ * Note that new `PARCOutputStream` is not created,
+ * only that the given `PARCOutputStream` reference count is incremented.
+ * Discard the reference by invoking `parcOutputStream_Release`.
+ *
+ * @param [in] stream A pointer to a `PARCOutputStream` instance.
+ *
+ * @return The input `PARCOutputStream` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcOutputStream_Create(parcFileOutputStream_Acquire(fileOutputStream),
+ * PARCFileOutputStreamAsPARCInputStream);
+ * PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ * parcOutputStream_Write(output, buffer);
+ *
+ * PARCOutputStream *x = parcOutputStream_Acquire(output);
+ *
+ * parcBuffer_Release(&x);
+ * parcOutputStream_Release(&output);
+ * }
+ * @endcode
+ * @see parcOutputStream_Release
+ */
+PARCOutputStream *parcOutputStream_Acquire(const PARCOutputStream *stream);
+
+/**
+ * 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 interface will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in] streamPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcOutputStream_Create(parcFileOutputStream_Acquire(fileOutputStream),
+ * PARCFileOutputStreamAsPARCInputStream);
+ * PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ * parcOutputStream_Write(output, buffer);
+ * parcOutputStream_Release(&output);
+ * }
+ * @endcode
+ * @see parcOutputStream_Acquire
+ * @see parcOutputStream_Create
+ */
+void parcOutputStream_Release(PARCOutputStream **streamPtr);
+#endif // libparc_parc_OutputStream_h
diff --git a/libparc/parc/algol/parc_PathName.c b/libparc/parc/algol/parc_PathName.c
new file mode 100755
index 00000000..e329ee88
--- /dev/null
+++ b/libparc/parc/algol/parc_PathName.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_Deque.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+#include <parc/algol/parc_PathName.h>
+
+struct parc_pathname {
+ bool isAbsolute;
+ PARCDeque *path;
+};
+
+static void
+_destroy(PARCPathName **pathNamePtr)
+{
+ PARCPathName *pathName = *pathNamePtr;
+
+ for (size_t i = 0; i < parcDeque_Size(pathName->path); i++) {
+ void *name = parcDeque_GetAtIndex(pathName->path, i);
+ parcMemory_Deallocate((void **) &name);
+ }
+ parcDeque_Release(&pathName->path);
+}
+
+static bool
+_pathNameSegmentEquals(const void *x, const void *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+ return strcmp((char *) x, (char *) y) == 0;
+}
+
+static void *
+_pathNameSegmentCopy(const void *x)
+{
+ return parcMemory_StringDuplicate(x, strlen(x));
+}
+
+static const PARCObjectDescriptor parcPathNameSegment_ObjectInterface = {
+ .destroy = (PARCObjectDestroy *) NULL,
+ .copy = (PARCObjectCopy *) _pathNameSegmentCopy,
+ .toString = (PARCObjectToString *) NULL,
+ .equals = (PARCObjectEquals *) _pathNameSegmentEquals,
+ .compare = (PARCObjectCompare *) NULL
+};
+
+parcObject_ExtendPARCObject(PARCPathName, _destroy, parcPathName_Copy, parcPathName_ToString,
+ parcPathName_Equals, NULL, NULL, NULL);
+
+PARCPathName *
+parcPathName_ParseToLimit(size_t limit, const char path[limit])
+{
+ PARCPathName *result = parcPathName_Create();
+
+ if (limit > 0) {
+ size_t index = 0;
+
+ if (path[index] == '/') {
+ result->isAbsolute = true;
+ index++;
+ }
+ while (path[index] != 0 && index < limit) {
+ while (path[index] == '/' && index < limit) {
+ index++;
+ }
+ if (path[index] != 0 && index < limit) {
+ size_t segment = index;
+ while (path[index] != 0 && path[index] != '/' && index < limit) {
+ index++;
+ }
+
+ parcDeque_Append(result->path, parcMemory_StringDuplicate(&path[segment], index - segment));
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCPathName *
+parcPathName_Parse(const char *path)
+{
+ return parcPathName_ParseToLimit(strlen(path), path);
+}
+
+PARCPathName *
+parcPathName_Create(void)
+{
+ PARCPathName *result = parcObject_CreateInstance(PARCPathName);
+
+ result->isAbsolute = false;
+ result->path = parcDeque_CreateObjectInterface(&parcPathNameSegment_ObjectInterface);
+ return result;
+}
+
+parcObject_ImplementAcquire(parcPathName, PARCPathName);
+
+parcObject_ImplementRelease(parcPathName, PARCPathName);
+
+PARCPathName *
+parcPathName_Copy(const PARCPathName *pathName)
+{
+ PARCPathName *result = parcObject_CreateInstance(PARCPathName);
+
+ result->isAbsolute = pathName->isAbsolute;
+ result->path = parcDeque_Copy(pathName->path);
+ return result;
+}
+
+bool
+parcPathName_Equals(const PARCPathName *x, const PARCPathName *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ if (x->isAbsolute == y->isAbsolute) {
+ return parcDeque_Equals(x->path, y->path);
+ }
+ return false;
+}
+
+bool
+parcPathName_IsAbsolute(const PARCPathName *pathName)
+{
+ return pathName->isAbsolute;
+}
+
+bool
+parcPathName_MakeAbsolute(PARCPathName *pathName, bool absolute)
+{
+ bool result = parcPathName_IsAbsolute(pathName);
+ pathName->isAbsolute = absolute;
+
+ return result;
+}
+
+PARCPathName *
+parcPathName_Prepend(PARCPathName *pathName, const char *name)
+{
+ parcDeque_Prepend(pathName->path, parcMemory_StringDuplicate(name, strlen(name)));
+ return pathName;
+}
+
+PARCPathName *
+parcPathName_Append(PARCPathName *pathName, const char *name)
+{
+ parcDeque_Append(pathName->path, parcMemory_StringDuplicate(name, strlen(name)));
+ return pathName;
+}
+
+char *
+parcPathName_GetAtIndex(const PARCPathName *pathName, size_t index)
+{
+ return (char *) parcDeque_GetAtIndex(pathName->path, index);
+}
+
+PARCPathName *
+parcPathName_Head(const PARCPathName *pathName, size_t size)
+{
+ PARCPathName *result = parcPathName_Create();
+ size_t maximum = parcPathName_Size(pathName) < size ? parcPathName_Size(pathName) : size;
+
+ for (size_t i = 0; i < maximum; i++) {
+ parcPathName_Append(result, parcPathName_GetAtIndex(pathName, i));
+ }
+
+ parcPathName_MakeAbsolute(result, parcPathName_IsAbsolute(pathName));
+
+ return result;
+}
+
+PARCPathName *
+parcPathName_Tail(const PARCPathName *pathName, size_t size)
+{
+ PARCPathName *result = parcPathName_Create();
+ if (size > parcPathName_Size(pathName)) {
+ size = parcPathName_Size(pathName);
+ }
+
+ for (size_t i = parcPathName_Size(pathName) - size; i < parcPathName_Size(pathName); i++) {
+ parcPathName_Prepend(result, parcPathName_GetAtIndex(pathName, i));
+ }
+
+ parcPathName_MakeAbsolute(result, false);
+
+ return result;
+}
+
+size_t
+parcPathName_Size(const PARCPathName *pathName)
+{
+ return parcDeque_Size(pathName->path);
+}
+
+PARCBufferComposer *
+parcPathName_BuildString(const PARCPathName *pathName, PARCBufferComposer *composer)
+{
+ char *separator = "/";
+
+ // an absolute path with no segments should just be '/'
+ if (parcPathName_IsAbsolute(pathName)) {
+ parcBufferComposer_PutString(composer, separator);
+ }
+
+ size_t length = parcDeque_Size(pathName->path);
+ if (length > 0) {
+ parcBufferComposer_PutString(composer, parcDeque_GetAtIndex(pathName->path, 0));
+ for (size_t i = 1; i < length; i++) {
+ parcBufferComposer_PutStrings(composer, separator, parcDeque_GetAtIndex(pathName->path, i), NULL);
+ }
+ }
+
+ return composer;
+}
+
+char *
+parcPathName_ToString(const PARCPathName *pathName)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcPathName_BuildString(pathName, composer);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+void
+parcPathName_Display(const PARCPathName *pathName, int indentation)
+{
+ if (pathName == NULL) {
+ parcDisplayIndented_PrintLine(indentation, "PARCPathName@NULL\n");
+ } else {
+ parcDisplayIndented_PrintLine(indentation, "PARCPathName@%p {\n", (void *) pathName);
+ parcDeque_Display(pathName->path, indentation + 1);
+ parcDisplayIndented_PrintLine(indentation, "}\n");
+ }
+}
diff --git a/libparc/parc/algol/parc_PathName.h b/libparc/parc/algol/parc_PathName.h
new file mode 100644
index 00000000..d02f8ef5
--- /dev/null
+++ b/libparc/parc/algol/parc_PathName.h
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_PathName.h
+ * @ingroup inputoutput
+ * @brief Path Name Manipulation
+ *
+ */
+#ifndef libparc_parc_PathName_h
+#define libparc_parc_PathName_h
+
+struct parc_pathname;
+typedef struct parc_pathname PARCPathName;
+
+#include <parc/algol/parc_BufferComposer.h>
+
+/**
+ * Create an empty, relative, `PARCPathName`.
+ *
+ * @return A pointer to a `PARCPathName` instance.
+ *
+ * @see {@link parcPathName_MakeAbsolute}
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPathName *result = parcPathName_Create();
+ * parcPathName_Destroy(&result);
+ * }
+ * <#example#>
+ * @endcode
+ */
+PARCPathName *parcPathName_Create(void);
+
+/**
+ * Parse a null-terminated C string as a `PARCPathName` limited to specific length.
+ * Components are separated by a single '/' character.
+ *
+ * @param [in] limit The limit to the length
+ * @param [in] path The string to parse
+ *
+ * @return A pointer to the new `PARCPathName`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCPathName *parcPathName_ParseToLimit(size_t limit, const char *path);
+
+/**
+ * Parse a null-terminated C string as a `PARCPathName`
+ * Components are separated by a single '/' character.
+ *
+ * @param [in] path The string to be parsed
+ * @return A pointer to the new `PARCPathName`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCPathName *parcPathName_Parse(const char *path);
+
+/**
+ * Acquire a new reference to an instance of `PARCPathName`.
+ *
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] pathName The instance of `PARCPathName` to which to refer.
+ *
+ * @return The same value as the input parameter @p pathName
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCPathName *parcPathName_Acquire(const PARCPathName *pathName);
+
+/**
+ * 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] pathNamePtr A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPathName *pathName = parcPathName_Parse("/tmp/foo");
+ *
+ * parcPathName_Release(&pathName);
+ * }
+ * @endcode
+ */
+void parcPathName_Release(PARCPathName **pathNamePtr);
+
+/**
+ * Determine if two `PARCPathName` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCPathName` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcPathName_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcPathName_Equals(x, y)` must return true if and only if
+ * `parcPathName_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcPathName_Equals(x, y)` returns true and
+ * `parcPathName_Equals(y, z)` returns true,
+ * then `parcPathName_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcPathName_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcPathName_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a `PARCPathName` instance.
+ * @param [in] y A pointer to a `PARCPathName` instance.
+ *
+ * @return true `PARCPathName` x and y are equal.
+ * @return false `PARCPathName` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPathName *a = parcPathName_Create();
+ * PARCPathName *b = parcPathName_Create();
+ *
+ * if (parcPathName_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ *
+ */
+bool parcPathName_Equals(const PARCPathName *x, const PARCPathName *y);
+
+/**
+ * Copy a pathName into a new instance of `PARCPathName`
+ *
+ * @param [in] pathName An instance of `PARCPathName` to be copied
+ *
+ * @return A new instance of `PARCPathName` that is a copy of @p pathName
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+PARCPathName *parcPathName_Copy(const PARCPathName *pathName);
+
+/**
+ * Return true if the instance of `PARCPathName` is absolute
+ *
+ * An absolute path name is a fully specified path starting at the root as the left-most segment.
+ * A relative path name is an incomplete path starting at an unspecified root.
+ *
+ * For example, an absolute UNIX file name path begins with a `/` character.
+ * `/foo/bar`, `/tmp/test` are both absolute path names.
+ *
+ * @param [in] pathName The instance of `PARCPathName` to test for absoluteness
+ * @return True is the path name is absolute, false otherwise.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcPathName_IsAbsolute(const PARCPathName *pathName);
+
+/**
+ * Make a `PARCPathName` absolute or relative.
+ *
+ * An absolute path name is a fully specified path starting at the root as the left-most segment.
+ * A relative path name is an incomplete path starting at an unspecified root.
+ *
+ * For example, an absolute UNIX file name path begins with a `/` character.
+ * `/foo/bar`, `/tmp/test` are both absolute path names.
+ *
+ *
+ * @param [in,out] pathName A pointer to a `PARCPathName` instance to be modified
+ * @param [in] absolute a flad as to whether the @p pathName should be set to absolute or relative; true indicates absolute
+ *
+ * @return true if the `PARCPathName` was previously an absolute path name.
+ * @return false if the `PARCPathName` was previously a relative path name.
+ *
+ * Example:
+ * @code
+ * {
+ * parcPathName_MakeAbsolute(pathName true)
+ * }
+ * @endcode
+ */
+bool parcPathName_MakeAbsolute(PARCPathName *pathName, bool absolute);
+
+/**
+ * Append a name segment to a `PARCPathName`
+ *
+ * The C string, `name` is copied.
+ *
+ * @param [in,out] pathName The instance of `PARCPathName` to modify
+ * @param [in] name A pointer to a null-terminated string. The contents are appended to the @p pathName.
+ *
+ * @return The input @p pathName
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+PARCPathName *parcPathName_Append(PARCPathName *pathName, const char *name);
+
+/**
+ * Prepend a name segment to a `PARCPathName`
+ *
+ * The C string, `name` is copied.
+ *
+ * @param [in,out] pathName The instance of `PARCPathName` to modify
+ * @param [in] name A pointer to a null-terminated string. The contents are prepended to the @p pathName.
+ *
+ * @return The input @p pathName
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+PARCPathName *parcPathName_Prepend(PARCPathName *pathName, const char *name);
+
+/**
+ * Create a new `PARCPathName` instance that consists of the head of an existing `PARCPathName`.
+ *
+ * If the original `PARCPathName` is an absolute path, the new `PARCPathName` will also be absolute.
+ * Otherwise, it will be a relative path.
+ *
+ * The new `PARCPathName` contains a copy of the requisite components of the orignal `PARCPathName`.
+ *
+ * @param [in] pathName The original `PARCPathName`
+ * @param [in] size The maximum number of path segments to include in the new `PARCPathName`.
+ *
+ * @return a Pointer to the new `PARCPathName`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCPathName *parcPathName_Head(const PARCPathName *pathName, size_t size);
+
+/**
+ * Create a new `PARCPathName` instance that consists of the tail of an existing `PARCPathName`.
+ *
+ * The new `PARCPathName` is a relative path and contains a copy of the requisite components of the orignal `PARCPathName`.
+ *
+ * @param [in] pathName The original `PARCPathName`
+ * @param [in] size The maximum number of path segments to include in the new `PARCPathName`.
+ *
+ * @return a Pointer to the new `PARCPathName`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCPathName *parcPathName_Tail(const PARCPathName *pathName, size_t size);
+
+/**
+ * Get a pointer to the null-terminated C string for the specified path name segment.
+ *
+ * @param [in] pathName A pointer to a `PARCPathName` instance.
+ * @param [in] index The index of the segment
+ *
+ * @return a pointer to the null-terminate C string for the specified path name segment
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+char *parcPathName_GetAtIndex(const PARCPathName *pathName, size_t index);
+
+/**
+ * Get the number of path segments in a `PARCPathName`.
+ *
+ * @param [in] pathName A pointer to a `PARCPathName` instance.
+ *
+ * @return The number of path segments in the `PARCPathName`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+size_t parcPathName_Size(const PARCPathName *pathName);
+
+/**
+ * Append a representation of the specified instance to the given {@link PARCBufferComposer}.
+ *
+ * @param [in] path A pointer to the `PARCPathName` whose representation should be added to the @p string.
+ * @param [in] string A pointer to the `PARCBufferComposer` to which to append the representation of @p path
+ *
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The given `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * parcPathName_BuildString(instance, result);
+ *
+ * PARCBuffer *string = parcBufferComposer_FinalizeBuffer(result);
+ * printf("Hello: %s\n", parcBuffer_ToString(string));
+ * parcBuffer_Release(&string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcPathName_BuildString(const PARCPathName *path, PARCBufferComposer *string);
+
+/**
+ * Produce a C string representation of the given `PARCPathName`.
+ *
+ * Produce an allocated, null-terminated string representation of the given `PARCPathName`.
+ * The result must be freed by the caller via the `parcMemory_Deallocate()` function.
+ *
+ * @param [in] pathName A pointer to the `PARCPathName` to convert to a `String`
+ *
+ * @return The string representation of @p pathName
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ */
+char *parcPathName_ToString(const PARCPathName *pathName);
+
+/**
+ * Print a human readable representation of the given `PARCPathName`.
+ *
+ * @param [in] pathName A pointer to the instance of `PARCPathName` to display.
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPathName *instance = parcPathName_Create();
+ *
+ * parcPathName_Display(instance, 0);
+ *
+ * parcPathName_Release(&instance);
+ * }
+ * @endcode
+ *
+ */
+void parcPathName_Display(const PARCPathName *pathName, int indentation);
+#endif // libparc_parc_PathName_h
diff --git a/libparc/parc/algol/parc_PriorityQueue.c b/libparc/parc/algol/parc_PriorityQueue.c
new file mode 100755
index 00000000..93744b2c
--- /dev/null
+++ b/libparc/parc/algol/parc_PriorityQueue.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * Priority Queue implemented over a Binary Heap.
+ *
+ * A Binary Heap will have average insert of O(1) and delete of O(log n). The worst case
+ * is O(log n) for both. The average and worst case FindMin is O(1).
+ *
+ * The binary heap is implemented as a "0"-based array, so for node index n, the
+ * children are at 2n+1 and 2n+2. Its parent is at floor((n-1)/2).
+ *
+ * The Heap property is a[n] <= a[2n+1] and a[k] <= a[2k+2]. We need to move things around
+ * sufficiently for this property to remain true.
+ *
+ */
+
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_PriorityQueue.h>
+
+typedef struct heap_entry {
+ void *data;
+} HeapEntry;
+
+struct parc_priority_queue {
+ HeapEntry *array;
+ size_t capacity; // how many elements are allocated
+ size_t size; // how many elements are used
+
+ PARCPriorityQueueCompareTo *compare;
+ PARCPriorityQueueDestroyer *destroyer;
+};
+
+/**
+ * 0-based array indexing, so use 2n+1
+ */
+static size_t
+_leftChildIndex(size_t elementIndex)
+{
+ return 2 * elementIndex + 1;
+}
+
+/**
+ * 0-based array indexing, so use 2n+2
+ * IMPORTANT: This must be a larger index than the left child,
+ * as the TrickleDown algorithm assumes that if the right child exists so
+ * does the left child.
+ */
+static size_t
+_rightChildIndex(size_t elementIndex)
+{
+ return 2 * elementIndex + 2;
+}
+
+/**
+ * 0-based array indexing, so use (n-1)/2
+ */
+static size_t
+_parentIndex(size_t elementIndex)
+{
+ return (elementIndex - 1) / 2;
+}
+
+/**
+ * Exchange the data between two array locations
+ */
+static void
+_swap(PARCPriorityQueue *queue, size_t firstIndex, size_t secondIndex)
+{
+ void *firstData = queue->array[firstIndex].data;
+ queue->array[firstIndex].data = queue->array[secondIndex].data;
+ queue->array[secondIndex].data = firstData;
+}
+
+/**
+ * See parcPriorityQueue_TrickleDown for full details
+ *
+ * Case 1: Right child exists and r.value < n.value && r.value < l.value
+ * In this case, swap(n.index, r.index) and set n.index = r.index.
+ * 50 6
+ * / \ ===> / \
+ * 9 6 9 50
+ *
+ * Case 2: Right child exists and r.value < n.value && l.value <= r.value
+ * In this case swap(n.index, l.index) and set n.index = l.index
+ * This makes sense by transitivity that l <= r < n, so swap(n,l) satisfies the invariant.
+ * 50 6
+ * / \ ===> / \
+ * 6 9 50 9
+ */
+static size_t
+_trickleRightChild(PARCPriorityQueue *queue, size_t elementIndex, size_t leftChildIndex, size_t rightChildIndex)
+{
+ if (queue->compare(queue->array[rightChildIndex].data, queue->array[elementIndex].data) < 0) {
+ if (queue->compare(queue->array[rightChildIndex].data, queue->array[leftChildIndex].data) < 0) {
+ // Case 1
+ _swap(queue, rightChildIndex, elementIndex);
+ elementIndex = rightChildIndex;
+ } else {
+ // Case 2
+ _swap(queue, leftChildIndex, elementIndex);
+ elementIndex = leftChildIndex;
+ }
+ }
+ return elementIndex;
+}
+
+/**
+ * See parcPriorityQueue_TrickleDown for full details
+ *
+ * Case 3: Left child exists (right does not) and l.value < n.value
+ * In this case, swap(n.index, l.index) and set n.index = l.index
+ * 50 6
+ * / \ ===> / \
+ * 6 x 50 x
+ */
+static size_t
+_trickleLeftChild(PARCPriorityQueue *queue, size_t elementIndex, size_t leftChildIndex)
+{
+ if (queue->compare(queue->array[leftChildIndex].data, queue->array[elementIndex].data) < 0) {
+ // Case 3
+ _swap(queue, leftChildIndex, elementIndex);
+ elementIndex = leftChildIndex;
+ }
+ return elementIndex;
+}
+
+/**
+ * Moves an element down the heap until it satisfies the heap invariant.
+ *
+ * The value of node n must be less than or equal to both the left child and right child, if
+ * they exist. Here's the algorithm by example. Let r.value, l.value and n.value be the values
+ * of the right, left and node. Let r.index, l.index, and n.index be their indicies.
+ *
+ * Case 1: Right child exists and r.value < n.value && r.value < l.value
+ * In this case, swap(n.index, r.index) and set n.index = r.index.
+ * 50 6
+ * / \ ===> / \
+ * 9 6 9 50
+ *
+ * Case 2: Right child exists and r.value < n.value && l.value <= r.value
+ * In this case swap(n.index, l.index) and set n.index = l.index
+ * This makes sense by transitivity that l <= r < n, so swap(n,l) satisfies the invariant.
+ * 50 6
+ * / \ ===> / \
+ * 6 9 50 9
+ *
+ * Case 3: Left child exists (right does not) and l.value < n.value
+ * In this case, swap(n.index, l.index) and set n.index = l.index
+ * 50 6
+ * / \ ===> / \
+ * 6 x 50 x
+ *
+ * Case 4: No child exists or already satisfies invariant
+ * Done
+ * 50 50
+ * / \ ===> / \
+ * x x x x
+ * OR
+ * 4 4
+ * / \ ===> / \
+ * 9 6 9 6
+ *
+ *
+ * @param [in] queue The priority queue to manipulate
+ * @param [in] elementIndex The root element (n above) to trickle down
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+_trickleDown(PARCPriorityQueue *queue, size_t elementIndex)
+{
+ bool finished = false;
+
+ while (!finished) {
+ size_t rightChildIndex = _rightChildIndex(elementIndex);
+ size_t leftChildIndex = _leftChildIndex(elementIndex);
+
+ if (rightChildIndex < queue->size) {
+ // Case 1 and Case 2
+ elementIndex = _trickleRightChild(queue, elementIndex, leftChildIndex, rightChildIndex);
+ } else if (leftChildIndex < queue->size) {
+ // Case 3
+ elementIndex = _trickleLeftChild(queue, elementIndex, leftChildIndex);
+ } else {
+ // Case 4, we're done
+ finished = true;
+ }
+ }
+}
+
+/**
+ * Move the item at elementIndex up the tree until it satisfies the invariant.
+ *
+ * This is used when we insert an element at the bottom of the heap. We bubble it up
+ * the heap until it satisfies the heap invariant (i.e. it's parent is less than or
+ * equal to it).
+ *
+ * @param [in] queue The priority queue to manipulate
+ * @param [in] elementIndex The 0-based index of the element to bubble up
+ */
+static void
+_bubbleUp(PARCPriorityQueue *queue, size_t elementIndex)
+{
+ size_t parentIndex = _parentIndex(elementIndex);
+ while (elementIndex > 0 && queue->compare(queue->array[elementIndex].data, queue->array[parentIndex].data) < 0) {
+ _swap(queue, elementIndex, parentIndex);
+ // now move up the ladder
+ elementIndex = parentIndex;
+ parentIndex = _parentIndex(elementIndex);
+ }
+
+ // At this point, it is either at the top (elementIndex = 0) or statisfies the heap invariant.
+}
+
+/**
+ * Add more elements to the backing aray
+ *
+ * Expand the array capacity. We use a fixed x2 expansion each time, though this might not
+ * be desirable when the capacity gets large.
+ *
+ * @param [in] queue The priority queue to manipulate
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static void
+_expand(PARCPriorityQueue *queue)
+{
+ queue->capacity *= 2;
+ queue->array = parcMemory_Reallocate(queue->array, sizeof(HeapEntry) * queue->capacity);
+}
+
+// ================================
+// Public API
+
+void
+parcPriorityQueue_ParcFreeDestroyer(void **elementPtr)
+{
+ assertNotNull(elementPtr, "Double pointer must be non-null");
+ assertNotNull(*elementPtr, "Double pointer must dereference to non-null");
+ void *element = *elementPtr;
+ parcMemory_Deallocate((void **) &element);
+ *elementPtr = NULL;
+}
+
+int
+parcPriorityQueue_Uint64CompareTo(const void *a, const void *b)
+{
+ uint64_t value_a = *((uint64_t *) a);
+ uint64_t value_b = *((uint64_t *) b);
+ if (value_a < value_b) {
+ return -1;
+ } else if (value_a > value_b) {
+ return +1;
+ }
+ return 0;
+}
+
+PARCPriorityQueue *
+parcPriorityQueue_Create(PARCPriorityQueueCompareTo *compare, PARCPriorityQueueDestroyer *destroyer)
+{
+ assertNotNull(compare, "Parameter compare must be non-null");
+
+ size_t initialSize = 128;
+ PARCPriorityQueue *queue = parcMemory_AllocateAndClear(sizeof(PARCPriorityQueue));
+ assertNotNull(queue, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCPriorityQueue));
+ queue->array = parcMemory_AllocateAndClear(sizeof(HeapEntry) * initialSize);
+ assertNotNull(queue->array, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(HeapEntry) * initialSize);
+ queue->capacity = initialSize;
+ queue->size = 0;
+ queue->compare = compare;
+ queue->destroyer = destroyer;
+
+ return queue;
+}
+
+void
+parcPriorityQueue_Destroy(PARCPriorityQueue **queuePtr)
+{
+ assertNotNull(queuePtr, "Double pointer must be non-null");
+ assertNotNull(*queuePtr, "Double pointer must dereference to non-null");
+ PARCPriorityQueue *queue = *queuePtr;
+ parcPriorityQueue_Clear(queue);
+ parcMemory_Deallocate((void **) &(queue->array));
+ parcMemory_Deallocate((void **) &queue);
+ *queuePtr = NULL;
+}
+
+bool
+parcPriorityQueue_Add(PARCPriorityQueue *queue, void *data)
+{
+ assertNotNull(queue, "Parameter queue must be non-null");
+ assertNotNull(data, "Parameter data must be non-null");
+
+ if (queue->size + 1 > queue->capacity) {
+ _expand(queue);
+ }
+
+ // insert at the end of the array
+ queue->array[queue->size].data = data;
+
+ // increment the size before calling bubble up so invariants are true (i.e.
+ // the index we're giving to BubbleUp is within the array size.
+ queue->size++;
+ _bubbleUp(queue, queue->size - 1);
+
+ // we always allow duplicates, so always return true
+ return true;
+}
+
+void
+parcPriorityQueue_Clear(PARCPriorityQueue *queue)
+{
+ assertNotNull(queue, "Parameter queue must be non-null");
+ if (queue->destroyer != NULL) {
+ for (size_t i = 0; i < queue->size; i++) {
+ queue->destroyer(&queue->array[i].data);
+ }
+ }
+
+ queue->size = 0;
+}
+
+void *
+parcPriorityQueue_Peek(PARCPriorityQueue *queue)
+{
+ assertNotNull(queue, "Parameter queue must be non-null");
+ if (queue->size > 0) {
+ return queue->array[0].data;
+ }
+ return NULL;
+}
+
+void *
+parcPriorityQueue_Poll(PARCPriorityQueue *queue)
+{
+ assertNotNull(queue, "Parameter queue must be non-null");
+ if (queue->size > 0) {
+ void *data = queue->array[0].data;
+
+ queue->size--;
+
+ // if size == 1, then this is a no-op
+ queue->array[0].data = queue->array[queue->size].data;
+
+ // make sure the head satisifies the heap invariant
+ _trickleDown(queue, 0);
+
+ return data;
+ }
+
+ return NULL;
+}
+
+size_t
+parcPriorityQueue_Size(const PARCPriorityQueue *queue)
+{
+ assertNotNull(queue, "Parameter queue must be non-null");
+ return queue->size;
+}
diff --git a/libparc/parc/algol/parc_PriorityQueue.h b/libparc/parc/algol/parc_PriorityQueue.h
new file mode 100755
index 00000000..45a6ffab
--- /dev/null
+++ b/libparc/parc/algol/parc_PriorityQueue.h
@@ -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.
+ */
+
+/**
+ * @file parc_PriorityQueue.h
+ * @ingroup datastructures
+ * @brief A priority queue (heap), where the top item is the minimum by the sort function.
+ *
+ * The user provides a sort function and the top item will be the minimum
+ * as per the < relation.
+ *
+ */
+
+#ifndef libparc_parc_PriorityQueue_h
+#define libparc_parc_PriorityQueue_h
+
+#include <stdlib.h>
+#include <stdbool.h>
+
+struct parc_priority_queue;
+typedef struct parc_priority_queue PARCPriorityQueue;
+
+typedef int (PARCPriorityQueueCompareTo)(const void *a, const void *b);
+typedef void (PARCPriorityQueueDestroyer)(void **elementPtr);
+
+/**
+ * Calls {@link parcMemory_Deallocate} to free the element
+ *
+ * A simple destroyer that only uses {@link parcMemory_Deallocate}.
+ *
+ * @param [in,out] elementPtr Double pointer to data item, will be NULL'd
+ *
+ * Example:
+ * @code
+ *
+ * PARCPriorityQueue *q = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, parcPriorityQueue_ParcFreeDestroyer);
+ * uint64_t *objectid = parcMemory_Allocate(sizeof(uint64_t));
+ * objectid = 100;
+ *
+ * // this will use parcPriorityQueue_Uint64CompareTo sort order
+ * parcPriorityQueue_Add(q, objectid);
+ *
+ * // this will use the ParcFreeDestroyer
+ * parcPriorityQueue_Destroy(&q);
+ * @endcode
+ */
+void parcPriorityQueue_ParcFreeDestroyer(void **elementPtr);
+
+/**
+ * Treats the parameters as `uint64_t` pointers and compares them via natural sort order.
+ *
+ * Treats the parameters as `uint64_t` pointers and compares them via natural sort order.
+ * Obeys standared CompareTo semantics.
+ *
+ * @param [in] a uint64_t pointer
+ * @param [in] b uint64_t pointer
+ *
+ * @return -1 if a < b
+ * @return 0 if a == b
+ * @return +1 if a > b
+ *
+ * Example:
+ * @code
+ *
+ * PARCPriorityQueue *q = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, parcPriorityQueue_ParcFreeDestroyer);
+ * uint64_t *objectid = parcMemory_Allocate(sizeof(uint64_t));
+ * objectid = 100;
+ *
+ * // this will use parcPriorityQueue_Uint64CompareTo sort order
+ * parcPriorityQueue_Add(q, objectid);
+ *
+ * // this will use the ParcFreeDestroyer
+ * parcPriorityQueue_Destroy(&q);
+ * @endcode
+ */
+int parcPriorityQueue_Uint64CompareTo(const void *a, const void *b);
+
+
+/**
+ * Creates a priority queue with a given sort function.
+ *
+ * The sort function defines the ordering of the Priorty Queue. The minimum element
+ * will always be the head of the queue.
+ *
+ * The destroyer is called on data elements from {@link parcPriorityQueue_Clear()} and
+ * {@link parcPriorityQueue_Destroy()}. You may use {@linkparcPriorityQueue_ParcFreeDestroyer()} for
+ * elements that can be freed by only calling {@link parcMemory_Deallocate}.
+ *
+ * @param [in] compare Defines the sort order of the priority queue
+ * @param [in] destroyer Called for Clear and Destroy operations, may be NULL.
+ *
+ * @return non-null A pointer to a `PARCPriorityQueue`
+ *
+ * Example:
+ * @code
+ * PARCPriorityQueue *q = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, parcPriorityQueue_ParcFreeDestroyer);
+ * uint64_t *objectid = parcMemory_Allocate(sizeof(uint64_t));
+ * objectid = 100;
+ *
+ * // this will use parcPriorityQueue_Uint64CompareTo sort order
+ * parcPriorityQueue_Add(q, objectid);
+ *
+ * // this will use the ParcFreeDestroyer
+ * parcPriorityQueue_Destroy(&q);
+ * @endcode
+ */
+PARCPriorityQueue *parcPriorityQueue_Create(PARCPriorityQueueCompareTo *compare, PARCPriorityQueueDestroyer *destroyer);
+
+
+/**
+ * Destroy the queue and free remaining elements.
+ *
+ * Destroys the queue. If the destroyer was set in Create, then it will be called
+ * on all the remaining elements.
+ *
+ * @param [in,out] queuePtr Double pointer to allocated queue.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcPriorityQueue_Destroy(PARCPriorityQueue **queuePtr);
+
+/**
+ * Add an element to the priority queue, returning true if changed
+ *
+ * A "duplicate" is a data item that compares as equal to another item. The priority
+ * queue supports duplicates. It is not stable in regard to the ordering of duplicates.
+ * Because it supports duplicates, Add will always return true.
+ *
+ * The priority queue is unbounded.
+ *
+ * @param [in,out] queue The queue to modify
+ * @param [in] data The data to add to the queue, which must be comparable and not NULL
+ *
+ * @return true The data structure was modified by adding the new value
+ * @return false The data structure was not modified
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcPriorityQueue_Add(PARCPriorityQueue *queue, void *data);
+
+/**
+ * Removes all elements, calling the data structure's destroyer on each
+ *
+ * Remvoes all elements. If the data structure's destroyer is non-NULL, it will be called
+ * on each element.
+ *
+ * @param [in,out] queue The queue to modify
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcPriorityQueue_Clear(PARCPriorityQueue *queue);
+
+/**
+ * Returns the head element, but does not remove it.
+ *
+ * Returns the head element. The data structure is not modified. If the
+ * priority queue is empty, will return NULL.
+ *
+ * @param [in] queue The `PARCPriorityQueue` to query.
+ *
+ * @return non-null The head element
+ * @return null The queue is empty
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcPriorityQueue_Peek(PARCPriorityQueue *queue);
+
+/**
+ * Removes the head element from the queue and returns it.
+ *
+ * Removes the head element from the queue and returns it. If the queue is empty,
+ * it returns NULL.
+ *
+ * @param [in,out] queue The queue to query and modify.
+ *
+ * @return non-null The head element
+ * @return null The queue is empty
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcPriorityQueue_Poll(PARCPriorityQueue *queue);
+
+/**
+ * Returns the number of elements in the queue.
+ *
+ * @param [in] queue The `PARCPriorityQueue` to query.
+ *
+ * @return number The number of elements in the queue.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcPriorityQueue_Size(const PARCPriorityQueue *queue);
+#endif // libparc_parc_PriorityQueue_h
diff --git a/libparc/parc/algol/parc_Properties.c b/libparc/parc/algol/parc_Properties.c
new file mode 100644
index 00000000..19aea290
--- /dev/null
+++ b/libparc/parc/algol/parc_Properties.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_HashMap.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Memory.h>
+
+#include "parc_Properties.h"
+
+struct PARCProperties {
+ PARCHashMap *properties;
+};
+
+static void
+_parcProperties_Finalize(PARCProperties **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCProperties pointer.");
+ PARCProperties *instance = *instancePtr;
+
+ parcProperties_OptionalAssertValid(instance);
+
+ parcHashMap_Release(&instance->properties);
+}
+
+parcObject_ImplementAcquire(parcProperties, PARCProperties);
+
+parcObject_ImplementRelease(parcProperties, PARCProperties);
+
+parcObject_ExtendPARCObject(PARCProperties, _parcProperties_Finalize, parcProperties_Copy, parcProperties_ToString, parcProperties_Equals, parcProperties_Compare, parcProperties_HashCode, parcProperties_ToJSON);
+
+
+void
+parcProperties_AssertValid(const PARCProperties *instance)
+{
+ assertTrue(parcProperties_IsValid(instance),
+ "PARCProperties is not valid.");
+}
+
+PARCProperties *
+parcProperties_Create(void)
+{
+ PARCProperties *result = parcObject_CreateInstance(PARCProperties);
+
+ if (result != NULL) {
+ result->properties = parcHashMap_Create();
+ }
+
+ return result;
+}
+
+int
+parcProperties_Compare(const PARCProperties *instance, const PARCProperties *other)
+{
+ int result = 0;
+
+
+ return result;
+}
+
+PARCProperties *
+parcProperties_Copy(const PARCProperties *original)
+{
+ PARCProperties *result = parcObject_CreateInstance(PARCProperties);
+
+ if (result != NULL) {
+ result->properties = parcHashMap_Copy(original->properties);
+ }
+
+ return result;
+}
+
+void
+parcProperties_Display(const PARCProperties *properties, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCProperties@%p {", properties);
+ trapCannotObtainLockIf(parcHashMap_Lock(properties->properties) == false, "Cannot lock PARCProperties object.");
+
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator(properties->properties);
+ while (parcIterator_HasNext(iterator)) {
+ char *key = parcBuffer_ToString(parcIterator_Next(iterator));
+ const char *value = parcProperties_GetProperty(properties, key);
+ parcDisplayIndented_PrintLine(indentation + 1, "%s=%s", key, value);
+
+ parcMemory_Deallocate(&key);
+ }
+
+ parcIterator_Release(&iterator);
+
+ parcHashMap_Unlock(properties->properties);
+
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcProperties_Equals(const PARCProperties *x, const PARCProperties *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ return parcHashMap_Equals(x->properties, y->properties);
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcProperties_HashCode(const PARCProperties *instance)
+{
+ return parcHashMap_HashCode(instance->properties);
+}
+
+bool
+parcProperties_IsValid(const PARCProperties *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcProperties_ToJSON(const PARCProperties *properties)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ trapCannotObtainLockIf(parcHashMap_Lock(properties->properties) == false, "Cannot lock PARCProperties object.");
+
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator(properties->properties);
+ while (parcIterator_HasNext(iterator)) {
+ char *key = parcBuffer_ToString(parcIterator_Next(iterator));
+ const char *value = parcProperties_GetProperty(properties, key);
+ parcJSON_AddString(result, key, value);
+ parcMemory_Deallocate(&key);
+ }
+
+ parcIterator_Release(&iterator);
+
+ parcHashMap_Unlock(properties->properties);
+ return result;
+}
+
+PARCBufferComposer *
+parcProperties_BuildString(const PARCProperties *properties, PARCBufferComposer *composer)
+{
+ trapCannotObtainLockIf(parcHashMap_Lock(properties->properties) == false, "Cannot lock PARCProperties object.");
+
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator(properties->properties);
+ while (parcIterator_HasNext(iterator)) {
+ char *key = parcBuffer_ToString(parcIterator_Next(iterator));
+ const char *value = parcProperties_GetProperty(properties, key);
+ parcBufferComposer_PutStrings(composer, key, "=", value, "\n", NULL);
+ parcMemory_Deallocate(&key);
+ }
+
+ parcIterator_Release(&iterator);
+
+ parcHashMap_Unlock(properties->properties);
+ return composer;
+}
+
+char *
+parcProperties_ToString(const PARCProperties *properties)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcProperties_BuildString(properties, composer);
+ char *result = parcBufferComposer_ToString(composer);
+
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+void
+parcProperties_SetParsedProperty(PARCProperties *properties, char *string)
+{
+ char *equals = strchr(string, '=');
+ *equals++ = 0;
+
+ parcProperties_SetProperty(properties, string, equals);
+}
+
+bool
+parcProperties_SetProperty(PARCProperties *properties, const char *name, const char *string)
+{
+ bool result = false;
+
+ PARCBuffer *key = parcBuffer_AllocateCString(name);
+ PARCBuffer *value = parcBuffer_AllocateCString(string);
+
+ parcHashMap_Put(properties->properties, key, value);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+ return result;
+}
+
+const char *
+parcProperties_GetProperty(const PARCProperties *properties, const char *name)
+{
+ char *result = NULL;
+
+ PARCBuffer *key = parcBuffer_AllocateCString(name);
+ PARCBuffer *value = (PARCBuffer *) parcHashMap_Get(properties->properties, key);
+ if (value != NULL) {
+ result = parcBuffer_Overlay(value, 0);
+ }
+
+ parcBuffer_Release(&key);
+ return result;
+}
+
+const char *
+parcProperties_GetPropertyDefault(const PARCProperties *properties, const char *restrict name, const char *restrict defaultValue)
+{
+ char *result = (char *) defaultValue;
+
+ PARCBuffer *key = parcBuffer_AllocateCString(name);
+ PARCBuffer *value = (PARCBuffer *) parcHashMap_Get(properties->properties, key);
+ if (value != NULL) {
+ result = parcBuffer_Overlay(value, 0);
+ }
+
+ parcBuffer_Release(&key);
+ return result;
+}
+
+bool
+parcProperties_GetAsBoolean(const PARCProperties *properties, const char *name, bool defaultValue)
+{
+ bool result = defaultValue;
+
+ const char *value = parcProperties_GetProperty(properties, name);
+ if (value != NULL) {
+ if (strcmp(value, "true") == 0) {
+ result = true;
+ } else {
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+int64_t
+parcProperties_GetAsInteger(const PARCProperties *properties, const char *name, int64_t defaultValue)
+{
+ int64_t result = defaultValue;
+
+ const char *value = parcProperties_GetProperty(properties, name);
+ if (value != NULL) {
+ result = strtol(value, NULL, 10);
+ }
+
+ return result;
+}
+
+typedef struct {
+ PARCBuffer *element;
+ PARCIterator *hashMapIterator;
+} _PARCPropertiesIterator;
+
+static _PARCPropertiesIterator *
+_parcPropertiesIterator_Init(const PARCProperties *object)
+{
+ _PARCPropertiesIterator *state = parcMemory_AllocateAndClear(sizeof(_PARCPropertiesIterator));
+ state->hashMapIterator = parcHashMap_CreateKeyIterator(object->properties);
+ return state;
+}
+
+static bool
+_parcPropertiesIterator_HasNext(PARCProperties *properties __attribute__((unused)), _PARCPropertiesIterator *state)
+{
+ return parcIterator_HasNext(state->hashMapIterator);
+}
+
+static _PARCPropertiesIterator *
+_parcPropertiesIterator_Next(PARCProperties *properties __attribute__((unused)), _PARCPropertiesIterator *state)
+{
+ state->element = (PARCBuffer *) parcIterator_Next(state->hashMapIterator);
+ return state;
+}
+
+static void
+_parcPropertiesIterator_Remove(PARCProperties *properties __attribute__((unused)), _PARCPropertiesIterator **state)
+{
+ parcIterator_Remove((*state)->hashMapIterator);
+}
+
+static char *
+_parcPropertiesIterator_Element(PARCProperties *properties __attribute__((unused)), _PARCPropertiesIterator *state)
+{
+ return parcBuffer_Overlay(state->element, 0);
+}
+
+static void
+_parcPropertiesIterator_Fini(PARCProperties *properties __attribute__((unused)), _PARCPropertiesIterator *state)
+{
+ parcIterator_Release(&state->hashMapIterator);
+ parcMemory_Deallocate(&state);
+}
+
+PARCIterator *
+parcProperties_CreateIterator(const PARCProperties *properties)
+{
+ PARCIterator *iterator = parcIterator_Create((PARCObject *) properties,
+ (void *(*)(PARCObject *))_parcPropertiesIterator_Init,
+ (bool (*)(PARCObject *, void *))_parcPropertiesIterator_HasNext,
+ (void *(*)(PARCObject *, void *))_parcPropertiesIterator_Next,
+ (void (*)(PARCObject *, void **))_parcPropertiesIterator_Remove,
+ (void *(*)(PARCObject *, void *))_parcPropertiesIterator_Element,
+ (void (*)(PARCObject *, void *))_parcPropertiesIterator_Fini,
+ NULL);
+
+ return iterator;
+}
diff --git a/libparc/parc/algol/parc_Properties.h b/libparc/parc/algol/parc_Properties.h
new file mode 100644
index 00000000..6cca4d87
--- /dev/null
+++ b/libparc/parc/algol/parc_Properties.h
@@ -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.
+ */
+
+/**
+ * @file parc_Properties.h
+ * @ingroup types
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_Properties
+#define PARCLibrary_parc_Properties
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_Iterator.h>
+
+struct PARCProperties;
+typedef struct PARCProperties PARCProperties;
+
+/**
+ * Increase the number of references to a `PARCProperties` instance.
+ *
+ * Note that new `PARCProperties` is not created,
+ * only that the given `PARCProperties` reference count is incremented.
+ * Discard the reference by invoking `parcProperties_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCProperties instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * PARCProperties *b = parcProperties_Acquire();
+ *
+ * parcProperties_Release(&a);
+ * parcProperties_Release(&b);
+ * }
+ * @endcode
+ */
+PARCProperties *parcProperties_Acquire(const PARCProperties *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcProperties_OptionalAssertValid(_instance_)
+#else
+# define parcProperties_OptionalAssertValid(_instance_) parcProperties_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCProperties` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCProperties instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * parcProperties_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcProperties_Release(&b);
+ * }
+ * @endcode
+ */
+void parcProperties_AssertValid(const PARCProperties *instance);
+
+/**
+ * Create an instance of PARCProperties
+ *
+ * @return non-NULL A pointer to a valid PARCProperties instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * parcProperties_Release(&a);
+ * }
+ * @endcode
+ */
+PARCProperties *parcProperties_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 PARCProperties instance.
+ * @param [in] other A pointer to a valid PARCProperties 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
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ * PARCProperties *b = parcProperties_Create();
+ *
+ * if (parcProperties_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcProperties_Release(&a);
+ * parcProperties_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcProperties_Equals
+ */
+int parcProperties_Compare(const PARCProperties *instance, const PARCProperties *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 PARCProperties instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCProperties` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * PARCProperties *copy = parcProperties_Copy(&b);
+ *
+ * parcProperties_Release(&b);
+ * parcProperties_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCProperties *parcProperties_Copy(const PARCProperties *original);
+
+/**
+ * Print a human readable representation of the given `PARCProperties`.
+ *
+ * @param [in] instance A pointer to a valid PARCProperties instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * parcProperties_Display(a, 0);
+ *
+ * parcProperties_Release(&a);
+ * }
+ * @endcode
+ */
+void parcProperties_Display(const PARCProperties *instance, int indentation);
+
+/**
+ * Determine if two `PARCProperties` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCProperties` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcProperties_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcProperties_Equals(x, y)` must return true if and only if
+ * `parcProperties_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcProperties_Equals(x, y)` returns true and
+ * `parcProperties_Equals(y, z)` returns true,
+ * then `parcProperties_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcProperties_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcProperties_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCProperties instance.
+ * @param [in] y A pointer to a valid PARCProperties instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ * PARCProperties *b = parcProperties_Create();
+ *
+ * if (parcProperties_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcProperties_Release(&a);
+ * parcProperties_Release(&b);
+ * }
+ * @endcode
+ * @see parcProperties_HashCode
+ */
+bool parcProperties_Equals(const PARCProperties *x, const PARCProperties *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 parcProperties_Equals} method,
+ * then calling the {@link parcProperties_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 parcProperties_Equals} function,
+ * then calling the `parcProperties_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCProperties instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * uint32_t hashValue = parcProperties_HashCode(buffer);
+ * parcProperties_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcProperties_HashCode(const PARCProperties *instance);
+
+/**
+ * Determine if an instance of `PARCProperties` 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 PARCProperties instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * if (parcProperties_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcProperties_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcProperties_IsValid(const PARCProperties *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCProperties` 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
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * parcProperties_Release(&a);
+ * }
+ * @endcode
+ */
+void parcProperties_Release(PARCProperties **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCProperties 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
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * PARCJSON *json = parcProperties_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcProperties_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcProperties_ToJSON(const PARCProperties *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCProperties`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCProperties 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
+ * {
+ * PARCProperties *a = parcProperties_Create();
+ *
+ * char *string = parcProperties_ToString(a);
+ *
+ * parcProperties_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcProperties_Display
+ */
+char *parcProperties_ToString(const PARCProperties *instance);
+
+/**
+ * Append a representation of the specified `PARCProperties` instance to the given `PARCBufferComposer`.
+ *
+ * @param [in] properties A pointer to a `PARCProperties` 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();
+ *
+ * parcProperties_BuildString(instance, result);
+ *
+ * char *string = parcBufferComposer_ToString(result);
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate(string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcProperties_BuildString(const PARCProperties *properties, PARCBufferComposer *composer);
+
+/**
+ * Set the named property to @p value.
+ *
+ *
+ * @param [in] properties A pointer to a valid `PARCProperties` instance.
+ * @param [in] name A pointer to a nul-terminate, C string name for the property.
+ * @param [in] value A A pointer to a nul-terminate, C string name for the value of the property.
+ *
+ * @return true <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcProperties_SetProperty(PARCProperties *properties, const char *name, const char *value);
+
+
+void parcProperties_SetParsedProperty(PARCProperties *properties, char *string);
+
+/**
+ * Get the string value of the named property.
+ *
+ * @param [in] properties A pointer to a valid PARCProperties intance.
+ * @param [in] name A pointer to a nul-terminated, C string containing the name of the property.
+ *
+ * @return non-NULL A nul-terminated C string containing the value of the named property.
+ * @return NULL The property was not found.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+const char *parcProperties_GetProperty(const PARCProperties *properties, const char *restrict name);
+
+/**
+ * Return the string value of the named property, if present.
+ * Otherwise return the default value.
+ *
+ * @param [in] properties A pointer to a valid PARCProperties instance.
+ * @param [in] name A pointer to a nul-terminated, C string containing the name of the property.
+ * @param [in] defaultValue A pointer to a nul-terminated, C string containing the name of the property.
+ *
+ * @return non-NULL A nul-terminated C string containing the value of the named property.
+ * @return NULL The property was not found, and the default property was NULL.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+const char *parcProperties_GetPropertyDefault(const PARCProperties *properties, const char *restrict name, const char *restrict defaultValue);
+
+/**
+ * Return the boolean value of the named property, if present.
+ * Otherwise return the default value.
+ *
+ * @param [in] properties A pointer to a valid PARCProperties instance.
+ * @param [in] name A pointer to a nul-terminated, C string containing the name of the property.
+ * @param [in] defaultValue The default boolean value.
+ *
+ * @return true A the property is set to true.
+ * @return false The property is either not present, or is not set to true.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcProperties_GetAsBoolean(const PARCProperties *properties, const char *name, bool defaultValue);
+
+/**
+ * Return the integer value of the named property, if present.
+ * Otherwise return the default value.
+ *
+ * @param [in] properties A pointer to a valid PARCProperties instance.
+ * @param [in] name A pointer to a nul-terminated, C string containing the name of the property.
+ * @param [in] defaultValue The default integer value.
+ *
+ * @return The integer value of the named property.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+int64_t parcProperties_GetAsInteger(const PARCProperties *properties, const char *name, int64_t defaultValue);
+
+/**
+ * Create a new instance of PARCIterator that iterates through the given PARCProperties.
+ * The returned value must be released via {@link parcIterator_Release}.
+ *
+ * @param [in] list A pointer to a valid `PARCProperties`.
+ *
+ * @see parcIterator_Release
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIterator *iterator = parcLinkedList_CreateIterator(hashMap);
+ *
+ * while (parcIterator_HasNext(iterator)) {
+ * PARCObject *object = parcIterator_Next(iterator);
+ * }
+ *
+ * parcIterator_Release(&iterator);
+ * }
+ * @endcode
+ */
+PARCIterator *parcProperties_CreateIterator(const PARCProperties *properties);
+#endif
diff --git a/libparc/parc/algol/parc_RandomAccessFile.c b/libparc/parc/algol/parc_RandomAccessFile.c
new file mode 100755
index 00000000..65bff1d1
--- /dev/null
+++ b/libparc/parc/algol/parc_RandomAccessFile.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_RandomAccessFile.h>
+
+#include <stdio.h>
+
+struct PARCRandomAccessFile {
+ char *fname;
+ FILE *fhandle;
+};
+
+static void
+_parcRandomAccessFile_Finalize(PARCRandomAccessFile **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCRandomAccessFile pointer.");
+ PARCRandomAccessFile *instance = *instancePtr;
+ if (instance->fhandle != NULL) {
+ fclose(instance->fhandle);
+ }
+ if (instance->fname != NULL) {
+ parcMemory_Deallocate(&instance->fname);
+ }
+}
+
+parcObject_ImplementAcquire(parcRandomAccessFile, PARCRandomAccessFile);
+
+parcObject_ImplementRelease(parcRandomAccessFile, PARCRandomAccessFile);
+
+parcObject_ExtendPARCObject(PARCRandomAccessFile, _parcRandomAccessFile_Finalize, NULL,
+ parcRandomAccessFile_ToString, parcRandomAccessFile_Equals, NULL,
+ parcRandomAccessFile_HashCode, parcRandomAccessFile_ToJSON);
+
+
+void
+parcRandomAccessFile_AssertValid(const PARCRandomAccessFile *instance)
+{
+ assertTrue(parcRandomAccessFile_IsValid(instance),
+ "PARCRandomAccessFile is not valid.");
+}
+
+void
+parcRandomAccessFile_Display(const PARCRandomAccessFile *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCRandomAccessFile@%p {", instance);
+ parcDisplayIndented_PrintLine(indentation + 1, "File: %s", instance->fname);
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+PARCHashCode
+parcRandomAccessFile_HashCode(const PARCRandomAccessFile *instance)
+{
+ return parcHashCode_Hash((uint8_t *) instance->fname, strlen(instance->fname));
+}
+
+bool
+parcRandomAccessFile_Equals(const PARCRandomAccessFile *x, const PARCRandomAccessFile *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (strcmp(x->fname, y->fname) == 0) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+bool
+parcRandomAccessFile_IsValid(const PARCRandomAccessFile *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = instance->fhandle != NULL;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcRandomAccessFile_ToJSON(const PARCRandomAccessFile *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ if (result != NULL) {
+ parcJSON_AddString(result, "fname", instance->fname);
+ }
+
+ return result;
+}
+
+char *
+parcRandomAccessFile_ToString(const PARCRandomAccessFile *instance)
+{
+ char *result = parcMemory_Format("PARCRandomAccessFile[%s]@%p\n", instance->fname, instance);
+ return result;
+}
+
+PARCRandomAccessFile *
+parcRandomAccessFile_Open(PARCFile *file)
+{
+ PARCRandomAccessFile *handle = parcObject_CreateAndClearInstance(PARCRandomAccessFile);
+ if (handle != NULL) {
+ char *fname = parcFile_ToString(file);
+ handle->fhandle = fopen(fname, "r+");
+ handle->fname = parcMemory_StringDuplicate(fname, strlen(fname));
+ parcMemory_Deallocate(&fname);
+ }
+ return handle;
+}
+
+bool
+parcRandomAccessFile_Close(PARCRandomAccessFile *fileHandle)
+{
+ assertNotNull(fileHandle->fhandle, "Can't fclose a null pointer. How did they get one anyway?");
+ bool result = fclose(fileHandle->fhandle) == 0;
+ fileHandle->fhandle = NULL;
+ parcMemory_Deallocate(&fileHandle->fname);
+ fileHandle->fname = NULL;
+ return result;
+}
+
+// read (count * size) bytes into the provided buffer, and return the number of bytes actually read
+size_t
+parcRandomAccessFile_Read(PARCRandomAccessFile *fileHandle, PARCBuffer *buffer)
+{
+ size_t length = parcBuffer_Remaining(buffer);
+ size_t numBytes = fread(parcBuffer_Overlay(buffer, length), 1, length, fileHandle->fhandle);
+ return numBytes;
+}
+
+// write (count * size) bytes from `buffer` to the file, and return the number of bytes actually written
+size_t
+parcRandomAccessFile_Write(PARCRandomAccessFile *fileHandle, PARCBuffer *buffer)
+{
+ size_t length = parcBuffer_Remaining(buffer);
+ size_t numBytes = fwrite(parcBuffer_Overlay(buffer, length), 1, length, fileHandle->fhandle);
+ return numBytes;
+}
+
+size_t
+parcRandomAccessFile_Seek(PARCRandomAccessFile *fileHandle, long offset, PARCRandomAccessFilePosition position)
+{
+ size_t result = 0;
+ switch (position) {
+ case PARCRandomAccessFilePosition_Start:
+ result = fseek(fileHandle->fhandle, offset, SEEK_SET); // beginning of the file
+ break;
+ case PARCRandomAccessFilePosition_Current:
+ result = fseek(fileHandle->fhandle, offset, SEEK_CUR); // current offset
+ break;
+ case PARCRandomAccessFilePosition_End:
+ result = fseek(fileHandle->fhandle, offset, SEEK_END); // end of the file
+ break;
+ default:
+ assertTrue(false, "Invalid position %d", position);
+ }
+ return result;
+}
diff --git a/libparc/parc/algol/parc_RandomAccessFile.h b/libparc/parc/algol/parc_RandomAccessFile.h
new file mode 100755
index 00000000..f4f20150
--- /dev/null
+++ b/libparc/parc/algol/parc_RandomAccessFile.h
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_RandomAccessFile.h
+ * @ingroup inputoutput
+ * @brief A wrapper that provides random access to a file.
+ *
+ */
+#ifndef PARCLibrary_RandomAccessFile
+#define PARCLibrary_RandomAccessFile
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_File.h>
+
+struct PARCRandomAccessFile;
+typedef struct PARCRandomAccessFile PARCRandomAccessFile;
+
+typedef enum {
+ PARCRandomAccessFilePosition_Start,
+ PARCRandomAccessFilePosition_End,
+ PARCRandomAccessFilePosition_Current
+} PARCRandomAccessFilePosition;
+
+/**
+ * Increase the number of references to a `PARCRandomAccessFile` instance.
+ *
+ * Note that new `PARCRandomAccessFile` is not created,
+ * only that the given `PARCRandomAccessFile` reference count is incremented.
+ * Discard the reference by invoking `parcRandomAccessFile_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCRandomAccessFile instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(..);
+ *
+ * PARCRandomAccessFile *b = parcRandomAccessFile_Acquire();
+ *
+ * parcRandomAccessFile_Release(&a);
+ * parcRandomAccessFile_Release(&b);
+ * }
+ * @endcode
+ */
+PARCRandomAccessFile *parcRandomAccessFile_Acquire(const PARCRandomAccessFile *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcRandomAccessFile_OptionalAssertValid(_instance_)
+#else
+# define parcRandomAccessFile_OptionalAssertValid(_instance_) parcRandomAccessFile_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCRandomAccessFile` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCRandomAccessFile instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(..);
+ *
+ * parcRandomAccessFile_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcRandomAccessFile_Release(&b);
+ * }
+ * @endcode
+ */
+void parcRandomAccessFile_AssertValid(const PARCRandomAccessFile *instance);
+
+/**
+ * Print a human readable representation of the given `PARCRandomAccessFile`.
+ *
+ * @param [in] instance A pointer to a valid PARCRandomAccessFile instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(..);
+ *
+ * parcRandomAccessFile_Display(a, 0);
+ *
+ * parcRandomAccessFile_Release(&a);
+ * }
+ * @endcode
+ */
+void parcRandomAccessFile_Display(const PARCRandomAccessFile *instance, int indentation);
+
+/**
+ * Determine if two `PARCRandomAccessFile` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCRandomAccessFile` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcRandomAccessFile_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcRandomAccessFile_Equals(x, y)` must return true if and only if
+ * `parcRandomAccessFile_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcRandomAccessFile_Equals(x, y)` returns true and
+ * `parcRandomAccessFile_Equals(y, z)` returns true,
+ * then `parcRandomAccessFile_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcRandomAccessFile_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcRandomAccessFile_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCRandomAccessFile instance.
+ * @param [in] y A pointer to a valid PARCRandomAccessFile instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(..);
+ * PARCRandomAccessFile *b = parcRandomAccessFile_Open(..);
+ *
+ * if (parcRandomAccessFile_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcRandomAccessFile_Release(&a);
+ * parcRandomAccessFile_Release(&b);
+ * }
+ * @endcode
+ * @see parcRandomAccessFile_HashCode
+ */
+bool parcRandomAccessFile_Equals(const PARCRandomAccessFile *x, const PARCRandomAccessFile *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 parcRandomAccessFile_Equals} method,
+ * then calling the {@link parcRandomAccessFile_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 parcRandomAccessFile_Equals} function,
+ * then calling the `parcRandomAccessFile_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCRandomAccessFile instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open..();
+ *
+ * PARCHashCode hashValue = parcRandomAccessFile_HashCode(buffer);
+ * parcRandomAccessFile_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcRandomAccessFile_HashCode(const PARCRandomAccessFile *instance);
+
+/**
+ * Determine if an instance of `PARCRandomAccessFile` 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 PARCRandomAccessFile instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(..);
+ *
+ * if (parcRandomAccessFile_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcRandomAccessFile_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcRandomAccessFile_IsValid(const PARCRandomAccessFile *instance);
+
+/**
+ * Open a new `PARCRandomAccessFile` instance.
+ *
+ * @param [in] file A `PARCFile` which refers to the file to open for random access.
+ *
+ * @retval `PARCRandomAccessFile` A new instance
+ * @retval NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(file);
+ *
+ * if (parcRandomAccessFile_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcRandomAccessFile_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+PARCRandomAccessFile *parcRandomAccessFile_Open(PARCFile *file);
+
+/**
+ * Release a previously acquired reference to the given `PARCRandomAccessFile` 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
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(..);
+ *
+ * parcRandomAccessFile_Release(&a);
+ * }
+ * @endcode
+ */
+void parcRandomAccessFile_Release(PARCRandomAccessFile **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCRandomAccessFile 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
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(..);
+ *
+ * PARCJSON *json = parcRandomAccessFile_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcRandomAccessFile_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcRandomAccessFile_ToJSON(const PARCRandomAccessFile *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCRandomAccessFile`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCRandomAccessFile 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
+ * {
+ * PARCRandomAccessFile *a = parcRandomAccessFile_Open(..);
+ *
+ * char *string = parcRandomAccessFile_ToString(a);
+ *
+ * parcRandomAccessFile_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcRandomAccessFile_Display
+ */
+char *parcRandomAccessFile_ToString(const PARCRandomAccessFile *instance);
+
+/**
+ * Close a `PARCRandomAccessFile` instance.
+ *
+ * @param [in] fileHandle A `PARCRandomAccessFile.`
+ *
+ * @retval true The file was closed successfully.
+ * @retval false An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+ * PARCRandomAccessFile *handle = parcRandomAccessFile_Open(file);
+ *
+ * // use the handle
+ *
+ * parcRandomAccessFile_Close(handle);
+ * parcRandomAccessFile_Release(&handle);
+ * }
+ * @endcode
+ *
+ * @see parcRandomAccessFile_Open
+ */
+bool parcRandomAccessFile_Close(PARCRandomAccessFile *fileHandle);
+
+/**
+ * Read bytes into the provided `PARCBuffer` until the buffer limit is or the source EOF
+ * is reached.
+ *
+ * @param [in] fileHandle A `PARCRandomAccessFile` from which to read.
+ * @param [in,out] buffer A `PARCBuffer` into which data is read.
+ *
+ * @return The number of bytes read.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+ * PARCRandomAccessFile *handle = parcRandomAccessFile_Open(file);
+ *
+ * PARCBuffer *buffer = parcBuffer_Allocate(1024);
+ * size_t numBytes = parcRandomAccessFile_Read(handle, buffer);
+ *
+ * // use the data in `buffer`
+ *
+ * parcRandomAccessFile_Close(handle);
+ * parcRandomAccessFile_Release(&handle);
+ * }
+ * @endcode
+ *
+ * @see parcRandomAccessFile_Write
+ */
+size_t parcRandomAccessFile_Read(PARCRandomAccessFile *fileHandle, PARCBuffer *buffer);
+
+/**
+ * Write bytes from the provided `PARCBuffer` to the source file until the limit is reached.
+ *
+ * @param [in] fileHandle A `PARCRandomAccessFile` to which data is written.
+ * @param [in,out] buffer A `PARCBuffer` into which data is read.
+ *
+ * @return The number of bytes written.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+ * PARCRandomAccessFile *handle = parcRandomAccessFile_Open(file);
+ *
+ * PARCBuffer *buffer = parcBuffer_WrapCString("important data to go in the file");
+ * size_t numBytes = parcRandomAccessFile_Write(handle, buffer);
+ *
+ * // continue writing to the file if needed
+ *
+ * parcRandomAccessFile_Close(handle);
+ * parcRandomAccessFile_Release(&handle);
+ * }
+ * @endcode
+ *
+ * @see parcRandomAccessFile_Read
+ */
+size_t parcRandomAccessFile_Write(PARCRandomAccessFile *fileHandle, PARCBuffer *buffer);
+
+/**
+ * Seek to the position in the file specified as an offset from the position.
+ *
+ * The position can be one of:
+ * PARCRandomAccessFilePosition_Start
+ * PARCRandomAccessFilePosition_End
+ * PARCRandomAccessFilePosition_Current
+ *
+ * @param [in] fileHandle A `PARCRandomAccessFile` to which data is written.
+ * @param [in] offset The number of bytes to offset from the provided position.
+ * @param [in] position The base posititon from which the offset is calculated.
+ *
+ * @return The number of bytes seeked.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+ * PARCRandomAccessFile *handle = parcRandomAccessFile_Open(file);
+ *
+ * size_t fileSize = parcFile_GetFileSize(file);
+ * parcRandomAccessFile_Seek(handle, -1, PARCRandomAccessFilePosition_End);
+ *
+ * // use the last byte of the file
+ *
+ * parcRandomAccessFile_Close(handle);
+ * parcRandomAccessFile_Release(&handle);
+ * }
+ * @endcode
+ *
+ * @see parcRandomAccessFile_Read
+ */
+size_t parcRandomAccessFile_Seek(PARCRandomAccessFile *fileHandle, long offset, PARCRandomAccessFilePosition position);
+#endif
diff --git a/libparc/parc/algol/parc_ReadOnlyBuffer.c b/libparc/parc/algol/parc_ReadOnlyBuffer.c
new file mode 100755
index 00000000..25628ae8
--- /dev/null
+++ b/libparc/parc/algol/parc_ReadOnlyBuffer.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 <stdio.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_ReadOnlyBuffer.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+struct parc_readonly_buffer {
+ PARCBuffer *buffer;
+};
+
+static void
+_readOnlyBuffer_Finalize(PARCReadOnlyBuffer **bufferPtr)
+{
+ PARCReadOnlyBuffer *buffer = *bufferPtr;
+
+ parcBuffer_Release(&buffer->buffer);
+}
+
+parcObject_ExtendPARCObject(PARCReadOnlyBuffer, _readOnlyBuffer_Finalize, parcReadOnlyBuffer_Copy,
+ parcReadOnlyBuffer_ToString, parcReadOnlyBuffer_Equals, NULL, parcReadOnlyBuffer_HashCode, NULL);
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_Create(PARCBuffer *buffer)
+{
+ PARCReadOnlyBuffer *result = NULL;
+ if (buffer != NULL) {
+ result = parcObject_CreateInstance(PARCReadOnlyBuffer);
+ if (result != NULL) {
+ result->buffer = parcBuffer_WrapByteArray(parcBuffer_Array(buffer), parcBuffer_Position(buffer), parcBuffer_Limit(buffer));
+ }
+ }
+ return result;
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_Wrap(uint8_t *array, size_t arrayLength, size_t position, size_t limit)
+{
+ PARCReadOnlyBuffer *result = parcObject_CreateInstance(PARCReadOnlyBuffer);
+ if (result != NULL) {
+ result->buffer = parcBuffer_Wrap(array, arrayLength, position, limit);
+ }
+ return result;
+}
+
+parcObject_ImplementAcquire(parcReadOnlyBuffer, PARCReadOnlyBuffer);
+
+parcObject_ImplementRelease(parcReadOnlyBuffer, PARCReadOnlyBuffer);
+
+size_t
+parcReadOnlyBuffer_Capacity(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_Capacity(buffer->buffer);
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_Clear(PARCReadOnlyBuffer *buffer)
+{
+ parcBuffer_Clear(buffer->buffer);
+ return buffer;
+}
+
+bool
+parcReadOnlyBuffer_Equals(const PARCReadOnlyBuffer *x, const PARCReadOnlyBuffer *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ return parcBuffer_Equals(x->buffer, y->buffer);
+}
+
+PARCByteArray *
+parcReadOnlyBuffer_Array(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_Array(buffer->buffer);
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_Copy(const PARCReadOnlyBuffer *original)
+{
+ PARCReadOnlyBuffer *result = parcObject_CreateInstance(PARCReadOnlyBuffer);
+
+ if (result != NULL) {
+ result->buffer = parcBuffer_Copy(original->buffer);
+ }
+ return result;
+}
+
+size_t
+parcReadOnlyBuffer_ArrayOffset(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_ArrayOffset(buffer->buffer);
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_Rewind(PARCReadOnlyBuffer *buffer)
+{
+ parcBuffer_Rewind(buffer->buffer);
+ return buffer;
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_Reset(PARCReadOnlyBuffer *buffer)
+{
+ parcBuffer_Reset(buffer->buffer);
+ return buffer;
+}
+
+size_t
+parcReadOnlyBuffer_Limit(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_Limit(buffer->buffer);
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_Mark(PARCReadOnlyBuffer *buffer)
+{
+ parcBuffer_Mark(buffer->buffer);
+ return buffer;
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_SetLimit(PARCReadOnlyBuffer *buffer, size_t newLimit)
+{
+ parcBuffer_SetLimit(buffer->buffer, newLimit);
+
+ return buffer;
+}
+
+void *
+parcReadOnlyBuffer_Overlay(PARCReadOnlyBuffer *buffer, size_t length)
+{
+ return parcBuffer_Overlay(buffer->buffer, length);
+}
+
+size_t
+parcReadOnlyBuffer_Position(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_Position(buffer->buffer);
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_SetPosition(PARCReadOnlyBuffer *buffer, size_t newPosition)
+{
+ parcBuffer_SetPosition(buffer->buffer, newPosition);
+ return buffer;
+}
+
+size_t
+parcReadOnlyBuffer_Remaining(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_Remaining(buffer->buffer);
+}
+
+bool
+parcReadOnlyBuffer_HasRemaining(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_HasRemaining(buffer->buffer);
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_Flip(PARCReadOnlyBuffer *buffer)
+{
+ parcBuffer_Flip(buffer->buffer);
+ return buffer;
+}
+
+uint8_t
+parcReadOnlyBuffer_GetAtIndex(const PARCReadOnlyBuffer *buffer, size_t index)
+{
+ return parcBuffer_GetAtIndex(buffer->buffer, index);
+}
+
+PARCReadOnlyBuffer *
+parcReadOnlyBuffer_GetArray(PARCReadOnlyBuffer *buffer, uint8_t *array, size_t length)
+{
+ parcBuffer_GetBytes(buffer->buffer, length, array);
+ return buffer;
+}
+
+uint8_t
+parcReadOnlyBuffer_GetUint8(PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_GetUint8(buffer->buffer);
+}
+
+uint16_t
+parcReadOnlyBuffer_GetUint16(PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_GetUint16(buffer->buffer);
+}
+
+uint32_t
+parcReadOnlyBuffer_GetUint32(PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_GetUint32(buffer->buffer);
+}
+
+uint64_t
+parcReadOnlyBuffer_GetUint64(PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_GetUint64(buffer->buffer);
+}
+
+PARCHashCode
+parcReadOnlyBuffer_HashCode(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_HashCode(buffer->buffer);
+}
+
+char *
+parcReadOnlyBuffer_ToString(const PARCReadOnlyBuffer *buffer)
+{
+ return parcBuffer_ToString(buffer->buffer);
+}
+
+void
+parcReadOnlyBuffer_Display(const PARCReadOnlyBuffer *buffer, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCReadOnlyBuffer@%p {\n", (void *) buffer);
+ parcBuffer_Display(buffer->buffer, indentation + 1);
+ parcDisplayIndented_PrintLine(indentation, "}\n");
+}
diff --git a/libparc/parc/algol/parc_ReadOnlyBuffer.h b/libparc/parc/algol/parc_ReadOnlyBuffer.h
new file mode 100644
index 00000000..39dd6aa8
--- /dev/null
+++ b/libparc/parc/algol/parc_ReadOnlyBuffer.h
@@ -0,0 +1,834 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_ReadOnlyBuffer.h
+ * @ingroup memory
+ * @brief An indexable, linear buffer of read-only bytes.
+ *
+ * A `PARCReadOnlyBuffer` is a {@link PARCBuffer} that cannot be modified,
+ * but retains a position, limit and capacity.
+ *
+ */
+#ifndef libparc_parc_ReadOnlyBuffer_h
+#define libparc_parc_ReadOnlyBuffer_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_ByteArray.h>
+
+struct parc_readonly_buffer;
+typedef struct parc_readonly_buffer PARCReadOnlyBuffer;
+
+/**
+ * Create a new instance of `PARCBuPARCReadOnlyBuffer` referencing the content of the given {@link PARCBuffer}.
+ *
+ * A reference to the content of the given `PARCBuffer` is acquired.
+ *
+ * The new buffer's position, limit, capacity and mark will be the same as the given `PARCBuffer`.
+ *
+ * If capacity is zero, the buffer contains no underlying byte array.
+ *
+ * @param [in] buffer A pointed to a valid `PARCBuffer` instance.
+ *
+ * @return A `PARCReadOnlyBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * ...
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Create(PARCBuffer *buffer);
+
+/**
+ * Create a new instance of `PARCReadOnlyBuffer` using program supplied memory.
+ *
+ * The new buffer will be backed by the given byte array.
+ * Modifications to the array will be visible through the buffer.
+ *
+ * The new buffer's capacity will be @p arrayLength,
+ * its position will be @p position,
+ * its limit will be @p limit,
+ * and its mark will be undefined.
+ *
+ * Its backing array will be the given array,
+ * and its array offset will be zero.
+ *
+ * @param [in] array A pointer to a memory array.
+ * @param [in] arrayLength The length, in `uint8_t` units, of the memory array.
+ * @param [in] position The initial value for the buffer's position.
+ * @param [in] limit The initial value for the buffer's limit.
+ *
+ * @return A `PARCReadOnlyBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(array, 10, 0, 10);
+ *
+ * ...
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * }
+ * @endcode
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Wrap(uint8_t *array, size_t arrayLength, size_t position, size_t limit);
+
+/**
+ * Increase the number of references to a `PARCReadOnlyBuffer`.
+ *
+ * Note that new `PARCReadOnlyBuffer` is not created,
+ * only that the given `PARCReadOnlyBuffer` reference count is incremented.
+ * Discard the reference by invoking `parcBuffer_Release`.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` instance.
+ *
+ * @return The input `PARCReadOnlyBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * PARCReadOnlyBuffer *handle = parcReadOnlyBuffer_Acquire(roBuffer);
+ *
+ * ...
+ *
+ * parcReadOnlyBuffer_Release(&handle);
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Acquire(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Release a `PARCReadOnlyBuffer` reference.
+ *
+ * Only the last invocation where the reference count is decremented to zero,
+ * will actually destroy the `PARCReadOnlyBuffer`.
+ *
+ * @param [in,out] bufferPtr Pointer to the `PARCReadOnlyBuffer` instance to be released.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * ...
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+void parcReadOnlyBuffer_Release(PARCReadOnlyBuffer **bufferPtr);
+
+/**
+ * Returns this buffer's capacity.
+ *
+ * @param [in] buffer A pointer to a `PARCReadOnlyBuffer` instance.
+ *
+ * @return The given buffer's capacity.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(array, 10, 0, 10);
+ *
+ * size_t capacity = parcReadOnlyBuffer_Capacity(roBuffer);
+ * // capacity will be 10
+ *
+ * ...
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * }
+ * @endcode
+ */
+size_t parcReadOnlyBuffer_Capacity(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Clear the given buffer: The position is set to zero,
+ * the limit is set to the capacity,
+ * and the mark is invalidated.
+ *
+ * The mark is made invalid and any subsequent operation on the resulting
+ * `PARCBuffer` that requires the mark will abort until the mark
+ * is set again via `parcReadOnlyBuffer_Mark`.
+ *
+ * @param [in,out] buffer A pointer to the `PARCReadOnlyBuffer` instance to be modified.
+ *
+ * @return The value of @p buffer.
+ *
+ * Example:
+ * @code
+ * {
+ * parcReadOnlyBuffer_Clear(buffer);
+ * }
+ * @endcode
+ *
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Clear(PARCReadOnlyBuffer *buffer);
+
+/**
+ * Determine if two `PARCReadOnlyBuffer` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCReadOnlyBuffer` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcReadOnlyBuffer_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcReadOnlyBuffer_Equals(x, y)` must return true if and only if
+ * `parcReadOnlyBuffer_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcReadOnlyBuffer_Equals(x, y)` returns true and
+ * `parcReadOnlyBuffer_Equals(y, z)` returns true,
+ * then `parcReadOnlyBuffer_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcReadOnlyBuffer_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcReadOnlyBuffer_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] x A pointer to a `PARCReadOnlyBuffer` instance.
+ * @param [in] y A pointer to a `PARCReadOnlyBuffer` instance.
+ *
+ * @return true `PARCReadOnlyBuffer` x and y are equal.
+ * @return false `PARCReadOnlyBuffer` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ * PARCReadOnlyBuffer *roBuffer1 = parcReadOnlyBuffer_Create(array, 10, 0, 10);
+ * PARCReadOnlyBuffer *roBuffer2 = parcReadOnlyBuffer_Create(array, 10, 0, 10);
+ *
+ * if (parcReadOnlyBuffer_Equals(roBuffer1, roBuffer2)) {
+ * printf("ROBuffers are equal\n");
+ * } else {
+ * printf("ROBuffers are NOT equal\n");
+ * }
+ *
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * }
+ * @endcode
+ */
+bool parcReadOnlyBuffer_Equals(const PARCReadOnlyBuffer *x, const PARCReadOnlyBuffer *y);
+
+/**
+ * Return a pointer to the {@link PARCByteArray} that backs this buffer.
+ *
+ * If this `PARCReadOnlyBuffer` has a capacity of zero,
+ * there is no array of bytes and this function returns NULL.
+ *
+ * Modifications to the `PARCByteArray` will cause the returned array's content to be modified, and vice versa.
+ *
+ * The caller must obtain its own reference to the `PARCByteArray` if it intends to store it elsewhere.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The pointer to the `PARCByteArray` for the given `PARCReadOnlyBuffer`.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(array, 10, 0, 10);
+ *
+ * PARCByteArray *byteArray = parcReadOnlyBuffer_Array(roBuffer);
+ *
+ * ...
+ *
+ * parcByteArray_Release(&byteArray);
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * }
+ * @endcode
+ */
+PARCByteArray *parcReadOnlyBuffer_Array(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Create a copy of the given `PARCReadOnlyBuffer`.
+ *
+ * A new buffer is created as a complete copy of the original.
+ *
+ * @param [in] original A `PARCReadOnlyBuffer` instance.
+ *
+ * @return A `PARCReadOnlyBuffer` instance which is an identical, independent copy of the original.
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(array, 10, 0, 10);
+ *
+ * PARCReadOnlyBuffer *copy = parcReadOnlyBuffer_Copy(roBuffer);
+ *
+ * if (parcReadOnlyBuffer_Equals(roBuffer, copy)) {
+ * printf("ROBuffers are equal\n");
+ * }
+ *
+ * parcReadOnlyBuffer_Release(&copy);
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * }
+ * @endcode
+ *
+ * @see parcReadOnlyBuffer_Equals
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Copy(const PARCReadOnlyBuffer *original);
+
+/**
+ * Returns the offset within this buffer's backing {@link PARCByteArray} of the first element.
+ *
+ * Buffer position <i>p</i> corresponds to array index <i>p + arrayOffset()</i>.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The offset within this `PARCReadOnlyBuffer`'s array of the first element of the buffer
+ *
+ * Example:
+ * @code
+ * {
+ * uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(array, 10, 0, 10);
+ *
+ * size_t arrayOffset = parcReadOnlyBuffer_ArrayOffset(buffer);
+ * // offset will be 0 since the contents of the buffer start at the beginning
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * }
+ * @endcode
+ */
+size_t parcReadOnlyBuffer_ArrayOffset(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Rewinds this `PARCReadOnlyBuffer`: The position is set to zero and the mark is invalidated.
+ *
+ * The mark is made invalid and any subsequent operation on the resulting
+ * {@link PARCBuffer} that requires the mark will abort until the mark
+ * is set again via {@link parcBuffer_Mark}.
+ *
+ * @param [in,out] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The given `PARCReadOnlyBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ *
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * parcReadOnlyBuffer_Rewind(roBuffer);
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Rewind(PARCReadOnlyBuffer *buffer);
+
+/**
+ * Resets the given `PARCReadOnlyBuffer`'s position to the previously-marked position.
+ *
+ * Invoking this method neither changes nor invalidates the mark's value.
+ *
+ * @param [in,out] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The given `PARCReadOnlyBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint8(buffer, (uint8_t)'A');
+ *
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * parcReadOnlyBuffer_Reset(roBuffer);
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Reset(PARCReadOnlyBuffer *buffer);
+
+/**
+ * Return the given `PARCReadOnlyBuffer`'s limit.
+ *
+ * A buffer's limit is the index of the first element that should not be read or written.
+ * A buffer's limit is never negative and is never greater than its capacity.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The given `PARCReadOnlyBuffer`'s limit.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ *
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * size_t limit = parcReadOnlyBuffer_Limit(roBuffer);
+ * // limit will be 10
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+size_t parcReadOnlyBuffer_Limit(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Sets this buffer's mark at its position.
+ *
+ * @param [in,out] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The given `PARCReadOnlyBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * parcReadOnlyBuffer_Mark(roBuffer);
+ * // since the position was 0, the mark remains at 0
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Mark(PARCReadOnlyBuffer *buffer);
+
+/**
+ * Sets this `PARCReadOnlyBuffer`'s limit.
+ *
+ * If the position is larger than the new limit then it is set to the new limit.
+ *
+ * If the mark is defined and larger than the new limit then the mark is invalidated and
+ * any subsequent operation that requires the mark will abort until the mark
+ * is set again via {@link parcReadOnlyBuffer_Mark()}.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ * @param [in] newLimit The new limit value; must be no larger than this `PARCReadOnlyBuffer`'s capacity
+ *
+ * @return The given `PARCReadOnlyBuffer` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * parcReadOnlyBuffer_SetLimit(roBuffer, 8);
+ * // the limit is now 8, but the capacity is 10
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_SetLimit(PARCReadOnlyBuffer *buffer, size_t newLimit);
+
+/**
+ * Return a pointer to memory that can be cast to a specific type.
+ *
+ * This does not guarantee proper memory alignment.
+ * It is possible to obtain a pointer to memory that cannot be accessed
+ * as integer or other types because of CPU memory alignment requirements.
+ *
+ * @param [in,out] buffer A `PARCReadOnlyBuffer` pointer.
+ * @param [in] length The number of bytes to advance the buffer's position.
+ *
+ * @return non-NULL A pointer to memory.
+ *
+ * Example:
+ * @code
+ * {
+ * char *expected = "Hello World";
+ * struct timeval theTime = { .tv_sec = 123, .tv_usec = 456};
+ *
+ * PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint16_t) + strlen(expected) + sizeof(theTime));
+ *
+ * parcBuffer_PutUint16(buffer, strlen(expected));
+ * parcBuffer_PutUint8(buffer, expected, strlen(expected));
+ * parcBuffer_PutUint8(buffer, &theTime, sizeof(theTime));
+ * parcBuffer_Flip();
+ *
+ * uint16_t length = parcBuffer_GetUint16(buffer);
+ *
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * char *actual = parcReadOnlyBuffer_Overlay(roBuffer, length);
+ *
+ * struct timeval *tm = parcReadOnlyBuffer_Overlay(roBuffer, sizeof(struct timeval));
+ * }
+ * @endcode
+ */
+void *parcReadOnlyBuffer_Overlay(PARCReadOnlyBuffer *buffer, size_t length);
+
+/**
+ * Return the given `PARCReadOnlyBuffer`'s position.
+ *
+ * A buffer's position is the index of the next element to be read or written.
+ * A buffer's position is never negative and is never greater than its limit.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The given `PARCReadOnlyBuffer`'s position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * size_t position = parcReadOnlyBuffer_Position(roBuffer);
+ * // position is zero since the position of the underlying buffer is also 0
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+size_t parcReadOnlyBuffer_Position(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Set the given `PARCReadOnlyBuffer`'s position.
+ *
+ * A buffer's position is the index of the next element to be read or written.
+ * A buffer's position is never negative and is never greater than its limit.
+ *
+ * If the mark is defined and larger than the new position then the mark
+ * is invalidated and any subsequent operation on the resulting
+ * `PARCReadOnlyBuffer` that requires the mark will abort until the mark
+ * is set again via `parcReadOnlyBuffer_Mark`.
+ *
+ * @param [in,out] buffer A `PARCReadOnlyBuffer` pointer.
+ * @param [in] newPosition The value of the new position which must be less than or equal to the buffer's current limit.
+ *
+ * @return The given `PARCReadOnlyBuffer`'s position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Create(parcBuffer_Allocate(10));
+ * parcReadOnlyBuffer_SetPosition(buffer, 5);
+ * parcReadOnlyBuffer_Remaining(buffer); // Returns 5.
+ * }
+ * @endcode
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_SetPosition(PARCReadOnlyBuffer *buffer, size_t newPosition);
+
+/**
+ * Returns the number of elements between the current position and the limit.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The number of elements remaining in this `PARCReadOnlyBuffer`.
+ *
+ * Example:
+ * @code
+ * {
+ * parcReadOnlyBuffer_SetPosition(buffer, 5);
+ * parcReadOnlyBuffer_Remaining(buffer); // Returns 5.
+ * }
+ * @endcode
+ */
+size_t parcReadOnlyBuffer_Remaining(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Tells whether there are any elements between the current position and the limit.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return true if, and only if, there is at least one element remaining in this `PARCReadOnlyBuffer`.
+ *
+ * Example:
+ * @code
+ * {
+ * parcReadOnlyBuffer_SetPosition(buffer, 5);
+ * bool remaining = parcReadOnlyBuffer_HasRemaining(buffer);
+ * // remaining is true, since #remaining = 5
+ * }
+ * @endcode
+ */
+bool parcReadOnlyBuffer_HasRemaining(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Set the limit to the current position, then set the position to zero.
+ * If the mark is defined, it is invalidated.
+ *
+ * @param [in,out] buffer The `PARCReadOnlyBuffer` pointer to be modified.
+ *
+ * @return The same value as `buffer`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutByte(buffer, 'X');
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * parcReadOnlyBuffer_Flip(roBuffer);
+ * uint8_t actual = parcReadOnlyBuffer_GetUint8(roBuffer);
+ *
+ * ...
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_Flip(PARCReadOnlyBuffer *buffer);
+
+/**
+ * Get the single uint8_t at the index specified.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ * @param [in] index The index from which to retrieve the single byte in the buffer.
+ *
+ * @return The uint8_t value at the specified index
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutByte(buffer, 'X');
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * uint8_t byte = parcReadOnlyBuffer_GetAtIndex(roBuffer, 0);
+ *
+ * ...
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ */
+uint8_t parcReadOnlyBuffer_GetAtIndex(const PARCReadOnlyBuffer *buffer, size_t index);
+
+/**
+ * Read an array of length bytes from the given PARCReadOnlyBuffer, copying them to an array.
+ *
+ * The buffer's position is incremented by @p length.
+ *
+ * @param [in] buffer The `PARCReadOnlyBuffer` containing the `uint8_t` value.
+ * @param [out] array The `uint8_t` array to receive @p length bytes.
+ * @param [in] length The number of `uint8_t` elements to get..
+ *
+ * @return The given `PARCReadOnlyBuffer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(5);
+ * parcBuffer_PutUint8(buffer, 'A');
+ * parcBuffer_PutUint8(buffer, 'B');
+ * parcBuffer_PutUint8(buffer, 'C');
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ *
+ * uint8_t array[3];
+ * parcReadOnlyBuffer_GetArray(roBuffer, 3, array);
+ * // array[0] == 'A'
+ * // array[1] == 'B'
+ * // array[2] == 'C'
+ * }
+ * @endcode
+ *
+ * @see parcReadOnlyBuffer_Overlay
+ */
+PARCReadOnlyBuffer *parcReadOnlyBuffer_GetArray(PARCReadOnlyBuffer *buffer, uint8_t *array, size_t length);
+
+/**
+ * Get the single `uint8_t` at the current buffer position.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The `uint8_t` value at the current position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutByte(buffer, 'X');
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ * parcReadOnlyBuffer_Flip(roBuffer);
+ *
+ * uint8_t actual = parcReadOnlyBuffer_GetUint8(roBuffer);
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+uint8_t parcReadOnlyBuffer_GetUint8(PARCReadOnlyBuffer *buffer);
+
+/**
+ * Get the single `uint16_t` at the current buffer position.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The `uint16_t` value at the current position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint16(buffer, 0x1234);
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ * parcReadOnlyBuffer_Flip(roBuffer);
+ *
+ * uint16_t actual = parcReadOnlyBuffer_GetUint16(roBuffer);
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+uint16_t parcReadOnlyBuffer_GetUint16(PARCReadOnlyBuffer *buffer);
+
+/**
+ * Get the single `uint32_t` at the current buffer position.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` pointer.
+ *
+ * @return The `uint32_t` value at the current position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(10);
+ * parcBuffer_PutUint32(buffer, 0x12345678);
+ * PARCReadOnlyBuffer *roBuffer = parcReadOnlyBuffer_Create(buffer);
+ * parcReadOnlyBuffer_Flip(roBuffer);
+ *
+ * uint32_t actual = parcReadOnlyBuffer_GetUint32(roBuffer);
+ *
+ * parcReadOnlyBuffer_Release(&roBuffer);
+ * parcBuffer_Release(&buffer);
+ * }
+ * @endcode
+ */
+uint32_t parcReadOnlyBuffer_GetUint32(PARCReadOnlyBuffer *buffer);
+
+/**
+ * Read the unsigned 64-bit value in network order at the buffer's current position,
+ * and then increment the position by 8.
+ *
+ * @param [in,out] buffer The `PARCReadOnlyBuffer` containing the value.
+ *
+ * @return The `uint64_t` at the buffer's current position.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint64_t));
+ * parcBuffer_PutUint64(buffer, 0x1234567812345678);
+ * parcBuffer_Flip(buffer);
+ *
+ * PARCReadOnlyBuffer *readOnly = parcReadOnlyBuffer_Create(buffer);
+ * uint64_t actual = parcReadOnlyBuffer_GetUint64(&readOnly);
+ * }
+ * @endcode
+ */
+uint64_t parcReadOnlyBuffer_GetUint64(PARCReadOnlyBuffer *buffer);
+
+/**
+ * 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 {@link parcReadOnlyBuffer_HashCode} function must consistently return the same value,
+ * provided no information used in a corresponding {@link parcReadOnlyBuffer_Equals()}
+ * 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 parcReadOnlyBuffer_Equals} method,
+ * then calling the {@link parcReadOnlyBuffer_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 parcReadOnlyBuffer_Equals()} function,
+ * then calling the {@link parcReadOnlyBuffer_HashCode()}
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] buffer A pointer to the `PARCReadOnlyBuffer` instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * uint32_t hashValue = parcReadOnlyBuffer_HashCode(buffer);
+ * }
+ * @endcode
+ *
+ * @see parcReadOnlyBuffer_Equals
+ */
+PARCHashCode parcReadOnlyBuffer_HashCode(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Create a null-terminated C string containing the bytes of the given `PARCReadOnlyBuffer`.
+ *
+ * The string consists of the bytes from the current position of the buffer to its limit.
+ *
+ * @param [in] buffer A `PARCReadOnlyBuffer` instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to a null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * char *string = parcReadOnlyBuffer_ToString(buffer);
+ *
+ * parcMemory_Deallocate((void **)&string);
+ * }
+ * @endcode
+ */
+char *parcReadOnlyBuffer_ToString(const PARCReadOnlyBuffer *buffer);
+
+/**
+ * Print a human readable representation of the given `PARCReadOnlyBuffer`.
+ *
+ * Print on standard output a human readable representation of the given `PARCReadOnlyBuffer` indented by the level indicated.
+ *
+ * @param [in] buffer A pointer to the `PARCReadOnlyBuffer` instance.
+ * @param [in] indentation The number of tabs by which to indent the output strings.
+ *
+ * Example:
+ * @code
+ * {
+ * parcReadOnlyBuffer_Display(buffer, 0);
+ * }
+ * @endcode
+ */
+void parcReadOnlyBuffer_Display(const PARCReadOnlyBuffer *buffer, int indentation);
+#endif // libparc_parc_ReadOnlyBuffer_h
diff --git a/libparc/parc/algol/parc_SafeMemory.c b/libparc/parc/algol/parc_SafeMemory.c
new file mode 100644
index 00000000..1f152af9
--- /dev/null
+++ b/libparc/parc/algol/parc_SafeMemory.c
@@ -0,0 +1,658 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 substitute for posix_memalign(3) that
+ * establishes detectable boundaries around an allocated memory segment,
+ * records a stack backtrace for each allocation,
+ * detects buffer overruns and underruns by checking the boundaries when the memory is deallocated,
+ * and tries to prevent a stray pointer to reference the memory again once it's been deallocated.
+ *
+ * The allocated memory consists of three contiguous segments: the prefix, the memory usable by the caller, and the suffix.
+ * The memory usable by the caller is aligned as specified by the caller.
+ * The alignment must be a power of 2 greater than or equal to the size of a {@code void *}.
+ * <pre>
+ * +--base +-prefix +-- memory +-- suffix aligned on (void *)
+ * v v v v
+ * |________|PPPPPPPPPPPP|mmmmmmmmm...mmmm|___|SSSSSSSSS
+ * ^
+ * +-- variable padding
+ * </pre>
+ * Where '-' indicates padding, 'P' indicates the prefix data structure, 'm'
+ * indicates contiguous memory for use by the caller, and 'S" indicates the suffix data structure.
+ *
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#if defined(_WIN64)
+# define backtrace(...) (0)
+# define backtrace_symbols(...) 0
+# define backtrace_symbols_fd(...) ((void) 0)
+#elif defined(_WIN32)
+# define backtrace(...) (0)
+# define backtrace_symbols(...) 0
+# define backtrace_symbols_fd(...) ((void) 0)
+#elif defined(__ANDROID__)
+# define backtrace(...) (0)
+# define backtrace_symbols(...) 0
+# define backtrace_symbols_fd(...) ((void) 0)
+#elif defined(__APPLE__)
+# include <execinfo.h>
+#elif defined(__linux)
+# include <execinfo.h>
+#elif defined(__unix) // all unices not caught above
+# define backtrace(...) (0)
+# define backtrace_symbols(...) 0
+# define backtrace_symbols_fd(...) ((void) 0)
+#elif defined(__posix)
+# include <execinfo.h>
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/errno.h>
+#include <sys/queue.h>
+#include <pthread.h>
+
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <parc/algol/parc_StdlibMemory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+typedef struct memory_backtrace {
+ void **callstack;
+ int maximumFrameCount;
+ int actualFrameCount;
+} _MemoryBacktrace;
+
+static const uint32_t _parcSafeMemory_SuffixGuard = 0xcafecafe;
+typedef struct memory_suffix {
+ uint32_t guard;
+} _MemorySuffix;
+
+static const uint64_t _parcSafeMemory_PrefixMagic = 0xfacefacefaceface;
+static const uint64_t _parcSafeMemory_Guard = 0xdeaddeaddeaddead;
+static const uint64_t _parcSafeMemory_GuardAlreadyFreed = 0xBADDCAFEBADDCAFE;
+typedef struct memory_prefix {
+ uint64_t magic; // A magic number indicating the start of this data structure.
+ size_t requestedLength; // The number of bytes the caller requested.
+ size_t actualLength; // The number of bytes >= requestedLength to ensure the right alignment for the suffix.
+ size_t alignment; // The aligment required by the caller. Must be a power of 2 and >= sizeof(void *).
+ _MemoryBacktrace *backtrace; // A record of the caller's stack trace at the time of allocation.
+ uint64_t guard; // Try to detect underrun of the allocated memory.
+} _MemoryPrefix;
+
+typedef void *PARCSafeMemoryOrigin;
+
+typedef void *PARCSafeMemoryUsable;
+
+static PARCMemoryInterface *_parcMemory = &PARCStdlibMemoryAsPARCMemory;
+
+static pthread_mutex_t _parcSafeMemory_Mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+/**
+ * Return true if the given alignment value is greater than or equal to {@code sizeof(void *)} and
+ * is a power of 2.
+ *
+ * @param alignment
+ * @return
+ */
+static bool
+_alignmentIsValid(size_t alignment)
+{
+ return alignment >= sizeof(void *) && (alignment & (~alignment + 1)) == alignment;
+}
+
+/**
+ * Add two pointers arithmetically.
+ */
+// Should increment be a ssize_t, instead of size_t?
+static void *
+_pointerAdd(const void *base, const size_t increment)
+{
+ void *result = (void *) &((char *) base)[increment];
+ return result;
+}
+
+static size_t
+_computePrefixLength(const size_t alignment)
+{
+ return (sizeof(_MemoryPrefix) + alignment - 1) & ~(alignment - 1);
+}
+
+static size_t
+_computeUsableMemoryLength(const size_t requestedLength, const size_t alignment)
+{
+ return (requestedLength + alignment - 1) & ~(alignment - 1);
+}
+
+/**
+ * Compute the size of the suffix on an allocated chunk of managed memory that causes the
+ * first byte after this size to be aligned according to the given alignment value.
+ */
+static size_t
+_computeSuffixLength(size_t alignment __attribute__((unused)))
+{
+ return sizeof(_MemorySuffix);
+}
+
+/**
+ * Compute the total number of bytes necessary to store the entire Safe Memory structure.
+ * Given a size number of bytes for use by a client function,
+ * produce the total number of bytes necessary to store @p size
+ * number of bytes for use by a client function and the `_MemoryPrefix`
+ * and `_MemorySuffix` structures.
+ */
+static size_t
+_computeMemoryTotalLength(size_t requestedLength, size_t alignment)
+{
+ size_t result =
+ _computePrefixLength(alignment)
+ + _computeUsableMemoryLength(requestedLength, sizeof(void*))
+ + _computeSuffixLength(alignment);
+
+ return result;
+}
+
+/**
+ * Given the safe memory address, return a pointer to the _MemoryPrefix structure.
+ */
+static _MemoryPrefix *
+_parcSafeMemory_GetPrefix(const PARCSafeMemoryUsable *usable)
+{
+ _MemoryPrefix *prefix = _pointerAdd(usable, -sizeof(_MemoryPrefix));
+ return prefix;
+}
+
+/**
+ * Given a base address for memory Return a pointer to the {@link _MemorySuffix}
+ * structure for the given base pointer to allocated memory.
+ *
+ * @param base
+ * @return
+ */
+static _MemorySuffix *
+_parcSafeMemory_GetSuffix(const PARCSafeMemoryUsable *memory)
+{
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(memory);
+
+ _MemorySuffix *suffix = _pointerAdd(memory, prefix->actualLength);
+ return suffix;
+}
+
+static PARCSafeMemoryState
+_parcSafeMemory_GetPrefixState(const PARCSafeMemoryUsable *usable)
+{
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(usable);
+
+ if (prefix->guard == _parcSafeMemory_GuardAlreadyFreed) {
+ return PARCSafeMemoryState_ALREADYFREE;
+ }
+ if (prefix->guard != _parcSafeMemory_Guard) {
+ return PARCSafeMemoryState_UNDERRUN;
+ }
+ if (prefix->magic != _parcSafeMemory_PrefixMagic) {
+ return PARCSafeMemoryState_UNDERRUN;
+ }
+ if (!_alignmentIsValid(prefix->alignment)) {
+ return PARCSafeMemoryState_UNDERRUN;
+ }
+
+ return PARCSafeMemoryState_OK;
+}
+
+static PARCSafeMemoryOrigin *
+_parcSafeMemory_GetOrigin(const PARCSafeMemoryUsable *memory)
+{
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(memory);
+
+ return _pointerAdd(memory, -_computePrefixLength(prefix->alignment));
+}
+
+static PARCSafeMemoryState
+_parcSafeMemory_GetSuffixState(const PARCSafeMemoryUsable *memory)
+{
+ PARCSafeMemoryState result = PARCSafeMemoryState_OK;;
+ _MemorySuffix *suffix = _parcSafeMemory_GetSuffix(memory);
+ if (suffix->guard != _parcSafeMemory_SuffixGuard) {
+ result = PARCSafeMemoryState_OVERRUN;
+ }
+ return result;
+}
+
+/**
+ * Given a pointer to the base address of an allocated memory segment,
+ * compute and return a pointer to the corresponding {@link _MemorySuffix} for that same memory.
+ */
+static _MemorySuffix *
+_parcSafeMemory_FormatSuffix(const PARCSafeMemoryUsable *memory)
+{
+ _MemorySuffix *suffix = _parcSafeMemory_GetSuffix(memory);
+
+ suffix->guard = _parcSafeMemory_SuffixGuard;
+ return suffix;
+}
+
+static void
+_backtraceReport(const _MemoryBacktrace *backtrace, int outputFd)
+{
+ if (outputFd != -1) {
+ // Ignore the first entry as it points to this function and we just need to start at the calling function.
+ backtrace_symbols_fd(&backtrace->callstack[1], backtrace->actualFrameCount - 1, outputFd);
+ }
+}
+
+// This is a list of all memory allocations that were created by calls to Safe Memory.
+// Each element of the list is the pointer to the result returned to the caller of the memory allocation,
+// not a pointer to the base.
+struct safememory_entry {
+ LIST_ENTRY(safememory_entry) entries; // List
+ void *memory;
+};
+LIST_HEAD(, safememory_entry) head = LIST_HEAD_INITIALIZER(head);
+static pthread_mutex_t head_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void
+_parcSafeMemory_AddAllocation(void *memory)
+{
+ if (parcSafeMemory_Outstanding() == 0) {
+ LIST_INIT(&head); // Initialize the list.
+ }
+
+ struct safememory_entry *e = malloc(sizeof(struct safememory_entry)); // Insert this at the head.
+ e->memory = memory;
+
+ pthread_mutex_lock(&head_mutex);
+ LIST_INSERT_HEAD(&head, e, entries);
+ pthread_mutex_unlock(&head_mutex);
+}
+
+static void
+_parcSafeMemory_RemoveAllocation(void *memory)
+{
+ struct safememory_entry *e;
+ pthread_mutex_lock(&head_mutex);
+ LIST_FOREACH(e, &head, entries)
+ {
+ if (e->memory == memory) {
+ LIST_REMOVE(e, entries);
+ free(e);
+ pthread_mutex_unlock(&head_mutex);
+ return;
+ }
+ }
+
+ pthread_mutex_unlock(&head_mutex);
+ fprintf(stderr, "parcSafeMemory_RemoveAllocation: Destroying memory (%p) which is NOT in the allocated memory record. Double free?\n", memory);
+}
+
+static PARCSafeMemoryState
+_parcSafeMemory_GetState(const PARCSafeMemoryUsable *memory)
+{
+ PARCSafeMemoryState prefixState = _parcSafeMemory_GetPrefixState(memory);
+ if (prefixState != PARCSafeMemoryState_OK) {
+ return prefixState;
+ }
+ return _parcSafeMemory_GetSuffixState(memory);
+}
+
+static const char *
+_parcSafeMemory_StateToString(PARCSafeMemoryState status)
+{
+ switch (status) {
+ case PARCSafeMemoryState_OK: return "OK";
+ case PARCSafeMemoryState_MISMATCHED: return "MISMATCHED";
+ case PARCSafeMemoryState_UNDERRUN: return "UNDERRUN";
+ case PARCSafeMemoryState_OVERRUN: return "OVERRUN";
+ case PARCSafeMemoryState_NOTHINGALLOCATED: return "NOTHINGALLOCATED";
+ case PARCSafeMemoryState_ALREADYFREE: return "ALREADYFREE";
+ }
+ return "?";
+}
+
+static void
+_parcSafeMemory_Report(const PARCSafeMemoryUsable *safeMemory, int outputFd)
+{
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(safeMemory);
+
+ if (outputFd != -1) {
+ int charactersPrinted = dprintf(outputFd, "Memory %p (base %p) %s\n",
+ (void *) safeMemory,
+ (void *) prefix,
+ _parcSafeMemory_StateToString(_parcSafeMemory_GetState(safeMemory)));
+ trapUnexpectedStateIf(charactersPrinted < 0, "Cannot write to file descriptor %d", outputFd);
+ }
+ _backtraceReport(prefix->backtrace, outputFd);
+}
+
+uint32_t
+parcSafeMemory_ReportAllocation(int outputFd)
+{
+ uint32_t index = 0;
+ struct safememory_entry *e;
+
+ pthread_mutex_lock(&head_mutex);
+ LIST_FOREACH(e, &head, entries)
+ {
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(e->memory);
+ if (outputFd != -1) {
+ int charactersPrinted = dprintf(outputFd,
+ "\n%u SafeMemory@%p: %p={ .requestedLength=%zd, .actualLength=%zd, .alignment=%zd }\n",
+ index, e->memory, (void *) prefix, prefix->requestedLength, prefix->actualLength, prefix->alignment);
+ trapUnexpectedStateIf(charactersPrinted < 0, "Cannot write to file descriptor %d", outputFd)
+ {
+ pthread_mutex_unlock(&head_mutex);
+ }
+ }
+ _parcSafeMemory_Report(e->memory, outputFd);
+ index++;
+ }
+ pthread_mutex_unlock(&head_mutex);
+ return parcSafeMemory_Outstanding();
+}
+
+static void
+_backtraceDestroy(_MemoryBacktrace **backtrace)
+{
+ free((*backtrace)->callstack);
+ free(*backtrace);
+ *backtrace = 0;
+}
+
+static PARCSafeMemoryState
+_parcSafeMemory_Destroy(void **memoryPointer)
+{
+ pthread_mutex_lock(&_parcSafeMemory_Mutex);
+
+ if (parcSafeMemory_Outstanding() == 0) {
+ pthread_mutex_unlock(&_parcSafeMemory_Mutex);
+ return PARCSafeMemoryState_NOTHINGALLOCATED;
+ }
+
+ _parcSafeMemory_RemoveAllocation(*memoryPointer);
+
+ PARCSafeMemoryUsable *memory = *memoryPointer;
+
+ PARCSafeMemoryState state = _parcSafeMemory_GetState(memory);
+ trapUnexpectedStateIf(state != PARCSafeMemoryState_OK,
+ "Expected PARCSafeMemoryState_OK, actual %s (see parc_SafeMemory.h)",
+ _parcSafeMemory_StateToString(state))
+ {
+ pthread_mutex_unlock(&_parcSafeMemory_Mutex);
+ }
+
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(memory);
+ _backtraceDestroy(&prefix->backtrace);
+
+ PARCSafeMemoryOrigin *base = _parcSafeMemory_GetOrigin(memory);
+
+ memset(base, 0, _computeMemoryTotalLength(prefix->requestedLength, prefix->alignment));
+ prefix->guard = _parcSafeMemory_GuardAlreadyFreed;
+
+ ((PARCMemoryDeallocate *) _parcMemory->Deallocate)((void **) &base);
+
+ *memoryPointer = 0;
+
+ pthread_mutex_unlock(&_parcSafeMemory_Mutex);
+ return PARCSafeMemoryState_OK;
+}
+
+__attribute__((unused))
+static void
+_parcSafeMemory_DeallocateAll(void)
+{
+ struct safememory_entry *e;
+
+ pthread_mutex_lock(&head_mutex);
+ LIST_FOREACH(e, &head, entries)
+ {
+ _parcSafeMemory_Destroy(&e->memory);
+ }
+ pthread_mutex_unlock(&head_mutex);
+}
+
+static _MemoryBacktrace *
+_backtraceCreate(int maximumFrameCount)
+{
+ _MemoryBacktrace *result = malloc(sizeof(_MemoryBacktrace));
+ result->maximumFrameCount = maximumFrameCount;
+ result->callstack = calloc(result->maximumFrameCount, sizeof(void *));
+
+ result->actualFrameCount = backtrace(result->callstack, result->maximumFrameCount);
+
+ return result;
+}
+
+/**
+ * Format memory with a MemoryPrefix structure.
+ *
+ * @param origin The origin of the allocated memory (which is not the same as the start of usable memory).
+ * @param requestedLength The length of the extent of memory for general purpose use by the caller.
+ * @param alignment A power of 2 greater than or equal to {@code sizeof(void *)}.
+ * @return The pointer to the first address suitable for general purpose use by the caller.
+ */
+static PARCSafeMemoryUsable *
+_parcSafeMemory_FormatPrefix(PARCSafeMemoryOrigin *origin, size_t requestedLength, size_t alignment)
+{
+ int backTraceDepth = 20;
+
+ if (!_alignmentIsValid(alignment)) {
+ return NULL;
+ }
+ size_t prefixSize = _computePrefixLength(alignment);
+
+ // This abuts the prefix to the user memory, it does not start at the beginning
+ // of the aligned prefix region.
+ _MemoryPrefix *prefix = (_MemoryPrefix *) (origin + (prefixSize - sizeof(_MemoryPrefix)));
+
+ prefix->magic = _parcSafeMemory_PrefixMagic;
+ prefix->requestedLength = requestedLength;
+ prefix->actualLength = _computeUsableMemoryLength(requestedLength, sizeof(void*));
+ prefix->alignment = alignment;
+ prefix->backtrace = _backtraceCreate(backTraceDepth);
+ prefix->guard = _parcSafeMemory_Guard;
+
+ PARCSafeMemoryUsable *result = _pointerAdd(origin, prefixSize);
+
+ assertAligned(result, alignment, "Return value is not properly aligned to %zu", alignment);
+ return result;
+}
+
+/**
+ * Given a pointer to allocated memory and the length of bytes that will be used by the caller,
+ * format the prefix and suffix structures returning a pointer to the first properly aligned
+ * byte available to the client function.
+ */
+static void *
+_parcSafeMemory_FormatMemory(PARCSafeMemoryOrigin *origin, size_t length, size_t alignment)
+{
+ PARCSafeMemoryUsable *memory = _parcSafeMemory_FormatPrefix(origin, length, alignment);
+ if (memory != NULL) {
+ _parcSafeMemory_FormatSuffix(memory);
+ }
+
+ return memory;
+}
+
+int
+parcSafeMemory_MemAlign(void **memptr, size_t alignment, size_t requestedSize)
+{
+ if (!_alignmentIsValid(alignment)) {
+ return EINVAL;
+ }
+ if (requestedSize == 0) {
+ return EINVAL;
+ }
+
+ size_t totalSize = _computeMemoryTotalLength(requestedSize, alignment);
+ if (totalSize < requestedSize) {
+ return ERANGE;
+ }
+
+ pthread_mutex_lock(&_parcSafeMemory_Mutex);
+
+ void *base;
+ int failure = ((PARCMemoryMemAlign *) _parcMemory->MemAlign)(&base, alignment, totalSize);
+
+ if (failure != 0 || base == NULL) {
+ pthread_mutex_unlock(&_parcSafeMemory_Mutex);
+ return ENOMEM;
+ }
+
+ *memptr = _parcSafeMemory_FormatMemory(base, requestedSize, alignment);
+
+ _parcSafeMemory_AddAllocation(*memptr);
+ pthread_mutex_unlock(&_parcSafeMemory_Mutex);
+
+ return 0;
+}
+
+void *
+parcSafeMemory_Allocate(size_t requestedSize)
+{
+ void *result = NULL;
+
+ if (requestedSize != 0) {
+ size_t totalSize = _computeMemoryTotalLength(requestedSize, sizeof(void *));
+
+ if (totalSize >= requestedSize) {
+ pthread_mutex_lock(&_parcSafeMemory_Mutex);
+
+ void *base = ((PARCMemoryAllocate *) _parcMemory->Allocate)(totalSize);
+ if (base != NULL) {
+ result = _parcSafeMemory_FormatMemory(base, requestedSize, sizeof(void *));
+
+ _parcSafeMemory_AddAllocation(result);
+ }
+ pthread_mutex_unlock(&_parcSafeMemory_Mutex);
+ }
+ }
+ return result;
+}
+
+void *
+parcSafeMemory_AllocateAndClear(size_t requestedSize)
+{
+ void *memptr = parcSafeMemory_Allocate(requestedSize);
+ if (memptr != NULL) {
+ memset(memptr, 0, requestedSize);
+ }
+ return memptr;
+}
+
+bool
+parcSafeMemory_IsValid(const void *memory)
+{
+ bool result = true;
+
+ PARCSafeMemoryState state = _parcSafeMemory_GetState(memory);
+ if (state != PARCSafeMemoryState_OK) {
+ return false;
+ }
+
+ return result;
+}
+
+
+uint32_t
+parcSafeMemory_Outstanding(void)
+{
+ return ((PARCMemoryOutstanding *) _parcMemory->Outstanding)();
+}
+
+void *
+parcSafeMemory_Reallocate(void *original, size_t newSize)
+{
+ void *result;
+
+ result = parcSafeMemory_Allocate(newSize);
+
+ if (original == NULL) {
+ return result;
+ }
+
+ if (result != NULL) {
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(original);
+ size_t originalSize = prefix->requestedLength;
+
+ memcpy(result, original, originalSize);
+ parcSafeMemory_Deallocate(&original);
+ }
+ return result;
+}
+
+char *
+parcSafeMemory_StringDuplicate(const char *string, size_t length)
+{
+ size_t actualLength = strlen(string);
+ if (length < actualLength) {
+ actualLength = length;
+ }
+
+ char *result = parcSafeMemory_Allocate(actualLength + 1);
+ if (result != NULL) {
+ memcpy(result, string, actualLength);
+ result[actualLength] = 0;
+ }
+ return result;
+}
+
+void
+parcSafeMemory_Deallocate(void **pointer)
+{
+ _parcSafeMemory_Destroy(pointer);
+}
+
+void
+parcSafeMemory_Display(const void *memory, int indentation)
+{
+ if (memory == NULL) {
+ parcDisplayIndented_PrintLine(indentation, "PARCSafeMemory@NULL");
+ } else {
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(memory);
+
+ parcDisplayIndented_PrintLine(indentation, "PARCSafeMemory@%p {", (void *) memory);
+ parcDisplayIndented_PrintLine(indentation + 1,
+ "%p=[ magic=0x%" PRIx64 " requestedLength=%zd, actualLength=%zd, alignment=%zd, guard=0x%" PRIx64 "]",
+ _parcSafeMemory_GetOrigin(memory),
+ prefix->magic,
+ prefix->requestedLength,
+ prefix->actualLength,
+ prefix->alignment,
+ prefix->guard);
+
+ parcDisplayIndented_PrintMemory(indentation + 1, prefix->requestedLength, memory);
+
+ parcDisplayIndented_PrintLine(indentation, "}");
+ }
+}
+
+PARCMemoryInterface PARCSafeMemoryAsPARCMemory = {
+ .Allocate = (uintptr_t) parcSafeMemory_Allocate,
+ .AllocateAndClear = (uintptr_t) parcSafeMemory_AllocateAndClear,
+ .MemAlign = (uintptr_t) parcSafeMemory_MemAlign,
+ .Deallocate = (uintptr_t) parcSafeMemory_Deallocate,
+ .Reallocate = (uintptr_t) parcSafeMemory_Reallocate,
+ .Outstanding = (uintptr_t) parcSafeMemory_Outstanding,
+ .StringDuplicate = (uintptr_t) parcSafeMemory_StringDuplicate
+};
diff --git a/libparc/parc/algol/parc_SafeMemory.h b/libparc/parc/algol/parc_SafeMemory.h
new file mode 100644
index 00000000..0383fe39
--- /dev/null
+++ b/libparc/parc/algol/parc_SafeMemory.h
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_SafeMemory.h
+ * @ingroup developer
+ *
+ * @brief Facade to memory functions to make calls safer.
+ *
+ * This is a facade to interpose between an application and the standard C library functions posix_memalign(3),
+ * malloc(3), calloc(3), realloc(3) and free(3) that establishes detectable boundaries around an allocated memory segment,
+ * records a stack backtrace for each allocation,
+ * detects buffer overruns and underruns by checking the boundaries when the memory is deallocated,
+ * and tries to prevent a stray pointer to reference the memory again once it's been deallocated.
+ *
+ * The allocated memory consists of three contiguous segments: the prefix, the memory usable by the caller, and the suffix.
+ * The memory usable by the caller is aligned as specified by the caller.
+ * The alignment must be a power of 2 greater than or equal to the size of a {@code void *}.
+ * <pre>
+ * +--base +-prefix +-- aligned memory +-- suffix aligned on (void *)
+ * v v v v
+ * |________|PPPPPPPPPPPP|mmmmmmmmm...mmmm|___|SSSSSSSSS
+ * ^
+ * +-- variable padding
+ * </pre>
+ * Where '-' indicates padding, 'P' indicates the prefix data structure, 'm'
+ * indicates contiguous memory for use by the caller, and 'S" indicates the suffix data structure.
+ *
+ * To enable this facade, you must include the following line in your execution before any allocations are performed.
+ *
+ * @code
+ * {
+ * parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ * }
+ * @endcode
+ *
+ */
+#ifndef libparc_parc_SafeMemory_h
+#define libparc_parc_SafeMemory_h
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <parc/algol/parc_Memory.h>
+
+typedef enum parc_safety_memory_state {
+ PARCSafeMemoryState_OK = 0,
+ PARCSafeMemoryState_MISMATCHED = 1,
+ PARCSafeMemoryState_UNDERRUN = 2,
+ PARCSafeMemoryState_OVERRUN = 3,
+ PARCSafeMemoryState_NOTHINGALLOCATED = 4,
+ PARCSafeMemoryState_ALREADYFREE = 5
+} PARCSafeMemoryState;
+
+/**
+ * Generate a readable, null-terminated C string representation
+ * for the specified `PARCSafeMemoryState` type.
+ *
+ * @param [in] status A `PARCSafeMemoryState` value.
+ *
+ * @return A null-terminated C string that must be freed when done.
+ *
+ * Example:
+ * @code
+ * {
+ * size_t size = 100;
+ * uint32_t alignment = sizeof(void *);
+ * void *memory;
+ *
+ * memory = parcSafeMemory_Allocate(size);
+ * PARCSafeMemoryState state = parcSafeMemory_Destroy(&memory);
+ *
+ * printf("SafeMemoryState = %s\n", parcSafeMemoryState_ToString(state));
+ * }
+ * @endcode
+ */
+const char *parcSafeMemoryState_ToString(PARCSafeMemoryState status);
+
+/**
+ * Memory operations defined by {@link PARCMemoryInterface}
+ * and implemented by the Safe Memory functions.
+ */
+extern PARCMemoryInterface PARCSafeMemoryAsPARCMemory;
+
+/**
+ * Allocate Safe Memory.
+ *
+ * Allocate memory through the configured memory allocator, setting the environment to track this memory.
+ *
+ * @param [in] size The number of bytes necessary.
+ *
+ * @return non-NULL A pointer to allocated memory.
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * size_t size = 100;
+ * void *memory = parcSafeMemory_Allocate(size);
+ * }
+ * @endcode
+ */
+void *parcSafeMemory_Allocate(size_t size);
+
+/**
+ * Allocate Safe Memory.
+ *
+ * Allocate memory through the configured memory allocator, setting the environment to track this memory.
+ *
+ * @param [in] requestedSize The number of bytes necessary.
+ *
+ * @return non-NULL A pointer to allocated memory.
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * size_t size = 100;
+ * void *memory = parcSafeMemory_Allocate(size);
+ * }
+ * @endcode
+ */
+void *parcSafeMemory_AllocateAndClear(size_t requestedSize);
+
+/**
+ * Allocate aligned memory.
+ *
+ * Allocates @p size bytes of memory such that the allocation's
+ * base address is an exact multiple of alignment,
+ * and returns the allocation in the value pointed to by @p pointer.
+ *
+ * The requested alignment must be a power of 2 greater than or equal to `sizeof(void *)`.
+ *
+ * Memory that is allocated can be used as an argument in subsequent call `Reallocate`, however
+ * `Reallocate` is not guaranteed to preserve the original alignment.
+ *
+ * @param [out] pointer A pointer to a `void *` pointer that will be set to the address of the allocated memory.
+ * @param [in] alignment A power of 2 greater than or equal to `sizeof(void *)`
+ * @param [in] size The number of bytes to allocate.
+ *
+ * @return 0 Successful
+ * @return EINVAL The alignment parameter is not a power of 2 at least as large as sizeof(void *)
+ * @return ENOMEM Memory allocation error.
+ *
+ * Example:
+ * @code
+ * {
+ * void *allocatedMemory;
+ *
+ * int failure = parcSafeMemory_MemAlign(&allocatedMemory, sizeof(void *), 100);
+ * if (failure == 0) {
+ * parcSafeMemory_Deallocate(&allocatedMemory);
+ * // allocatedMemory is now equal to zero.
+ * }
+ * }
+ * @endcode
+ * @see `posix_memalign`
+ */
+int parcSafeMemory_MemAlign(void **pointer, size_t alignment, size_t size);
+
+/**
+ * Deallocate memory previously allocated with {@link parcSafeMemory_Allocate}
+ *
+ * The value pointed to by @p pointer will be set to NULL.
+ *
+ * @param [in,out] pointer A pointer to a pointer to the allocated memory.
+ *
+ * Example:
+ * @code
+ * {
+ * size_t size = 100;
+ * void *memory = parcSafeMemory_Allocate(size);
+ *
+ * parcSafeMemory_Deallocate(&memory);
+ * }
+ * @endcode
+ */
+void parcSafeMemory_Deallocate(void **pointer);
+
+/**
+ * A (mostly) suitable replacement for realloc(3).
+ * The primary difference is that it is an error if newSize is zero.
+ * If the newSize is equal to the old size, then NULL is returned.
+ *
+ * @param [in] original Pointer to the original memory
+ * @param [in] newSize The size of the newly re-allocated memory.
+ *
+ * @return Non-NULL A pointer to the newly allocated memory
+ * @return NULL An error occurred (newSize == oldSize, or newSize == 0)
+ *
+ * Example:
+ * @code
+ * {
+ * void *memory = parcSafeMemory_Allocate(100);
+ *
+ * size_t newLength = 0;
+ * unsigned char *newMemory = parcSafeMemory_Reallocate(memory, newLength);
+ *
+ * assertTrue(newMemory == NULL, "Expected NULL, actual %p", newMemory);
+ * }
+ * @endcode
+ */
+void *parcSafeMemory_Reallocate(void *original, size_t newSize);
+
+/**
+ * Duplicate the given null-terminated C string.
+ *
+ * @param [in] string A pointer to a null-terminated C string.
+ * @param [in] length The length of the string, not including the terminating null character.
+ *
+ * @return non-NULL Allocated Safe Memory containing the duplicate string. This must be freed via `parcSafeMemory_Deallocate`.
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * char *string = "hello world";
+ * char *actual = parcSafeMemory_StringDuplicate(string, strlen(string));
+ * ...
+ * }
+ * @endcode
+ *
+ * @see parcSafeMemory_Deallocate
+ */
+char *parcSafeMemory_StringDuplicate(const char *string, size_t length);
+
+/**
+ * Return the number of outstanding allocations.
+ *
+ * In practice, every allocation should be matched with a corresponding deallocation.
+ * This return the number of allocations that have not been deallocated.
+ *
+ * @return The number of outstanding allocations.
+ *
+ */
+uint32_t parcSafeMemory_Outstanding(void);
+
+/**
+ * Display information about outstanding memory allocations.
+ *
+ * To enable this function, you must include the following line in your execution before any allocations are performed.
+ *
+ * @code
+ * {
+ * parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ * }
+ * @endcode
+ *
+ * @param [in] outputFd Output file descriptor.
+ *
+ * @return The number of currenly outstanding allocations.
+ *
+ * Example:
+ * @code
+ * {
+ * parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ *
+ * ...
+ *
+ * FILE *fd = fopen ("log.txt", "w");
+ * size_t outstandingAllocations = parcSafeMemory_ReportAllocation(fd);
+ * }
+ * @endcode
+ */
+uint32_t parcSafeMemory_ReportAllocation(int outputFd);
+
+/**
+ * Determine if a pointer to Safe Memory is valid.
+ *
+ * Invalid indicates the memory is overrun or underrun.
+ *
+ * To enable this function, you must include the following line in your execution before any allocations are performed.
+ *
+ * @code
+ * {
+ * parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ * }
+ * @endcode
+ *
+ * @param [in] memory A pointer to previously allocated Safe Memory.
+ *
+ * @return true The memory is valid;
+ * @return false The memory is invalid;
+ *
+ * Example:
+ * @code
+ * {
+ * void *memory = parcSafeMemory_Allocate(100);
+ * if (parcSafeMemory_IsValid(memory) == false) {
+ * printf("Memory is invalid\n");
+ * }
+ * @endcode
+ */
+bool parcSafeMemory_IsValid(const void *memory);
+
+/**
+ * Print a human readable representation of the given PARC Safe Memory array.
+ *
+ * To enable this function, you must include the following line in your execution before any allocations are performed.
+ *
+ * @code
+ * {
+ * parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ * }
+ * @endcode
+ *
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ * @param [in] memory A pointer to the memory to display.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *instance = parcBuffer_Create();
+ *
+ * parcBuffer_Display(instance, 0);
+ *
+ * parcBuffer_Release(&instance);
+ * }
+ * @endcode
+ */
+void parcSafeMemory_Display(const void *memory, int indentation);
+#endif // libparc_parc_SafeMemory_h
diff --git a/libparc/parc/algol/parc_SortedList.c b/libparc/parc/algol/parc_SortedList.c
new file mode 100644
index 00000000..8a941701
--- /dev/null
+++ b/libparc/parc/algol/parc_SortedList.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <parc/algol/parc_SortedList.h>
+#include <parc/algol/parc_LinkedList.h>
+
+struct PARCSortedList {
+ PARCLinkedList *list;
+ PARCSortedListEntryCompareFunction compare;
+};
+
+static void
+_parcSortedList_Finalize(PARCSortedList **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCSortedList pointer.");
+ PARCSortedList *instance = *instancePtr;
+
+ parcSortedList_OptionalAssertValid(instance);
+
+ parcLinkedList_Release(&instance->list);
+}
+
+parcObject_ImplementAcquire(parcSortedList, PARCSortedList);
+
+parcObject_ImplementRelease(parcSortedList, PARCSortedList);
+
+parcObject_ExtendPARCObject(PARCSortedList, _parcSortedList_Finalize, parcSortedList_Copy, parcSortedList_ToString, parcSortedList_Equals, NULL, parcSortedList_HashCode, parcSortedList_ToJSON);
+
+
+void
+parcSortedList_AssertValid(const PARCSortedList *instance)
+{
+ assertTrue(parcSortedList_IsValid(instance),
+ "PARCSortedList is not valid.");
+}
+
+
+PARCSortedList *
+parcSortedList_Create(void)
+{
+ PARCSortedList *result = parcSortedList_CreateCompare(parcObject_Compare);
+
+ return result;
+}
+
+PARCSortedList *
+parcSortedList_CreateCompare(PARCSortedListEntryCompareFunction compare)
+{
+ PARCSortedList *result = parcObject_CreateInstance(PARCSortedList);
+
+ if (result != NULL) {
+ result->list = parcLinkedList_Create();
+ result->compare = compare;
+ }
+
+ return result;
+}
+
+PARCSortedList *
+parcSortedList_Copy(const PARCSortedList *original)
+{
+ PARCSortedList *result = parcObject_CreateInstance(PARCSortedList);
+
+ if (result != NULL) {
+ result->list = parcLinkedList_Copy(original->list);
+ }
+
+ return result;
+}
+
+void
+parcSortedList_Display(const PARCSortedList *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCSortedList@%p {", instance);
+ parcLinkedList_Display(instance->list, indentation + 1);
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcSortedList_Equals(const PARCSortedList *x, const PARCSortedList *y)
+{
+ return parcLinkedList_Equals(x->list, y->list);
+}
+
+PARCHashCode
+parcSortedList_HashCode(const PARCSortedList *instance)
+{
+ PARCHashCode result = parcLinkedList_HashCode(instance->list);
+
+ return result;
+}
+
+bool
+parcSortedList_IsValid(const PARCSortedList *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcSortedList_ToJSON(const PARCSortedList *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ return result;
+}
+
+char *
+parcSortedList_ToString(const PARCSortedList *instance)
+{
+ char *result = parcMemory_Format("PARCSortedList@%p\n", instance);
+
+ return result;
+}
+
+size_t
+parcSortedList_Size(const PARCSortedList *list)
+{
+ return parcLinkedList_Size(list->list);
+}
+
+PARCObject *
+parcSortedList_GetAtIndex(const PARCSortedList *list, const size_t index)
+{
+ return parcLinkedList_GetAtIndex(list->list, index);
+}
+
+PARCObject *
+parcSortedList_GetFirst(const PARCSortedList *list)
+{
+ return parcLinkedList_GetAtIndex(list->list, 0);
+}
+
+PARCObject *
+parcSortedList_GetLast(const PARCSortedList *list)
+{
+ return parcLinkedList_GetAtIndex(list->list, parcLinkedList_Size(list->list) - 1);
+}
+
+PARCObject *
+parcSortedList_RemoveFirst(PARCSortedList *list)
+{
+ PARCObject *result = parcLinkedList_RemoveFirst(list->list);
+
+ return result;
+}
+
+PARCObject *
+parcSortedList_RemoveLast(PARCSortedList *list)
+{
+ PARCObject *result = parcLinkedList_RemoveLast(list->list);
+
+ return result;
+}
+
+bool
+parcSortedList_Remove(PARCSortedList *list, const PARCObject *object)
+{
+ bool result = false;
+
+ PARCIterator *iterator = parcSortedList_CreateIterator(list);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCObject *o = parcIterator_Next(iterator);
+ if (parcObject_Equals(object, o)) {
+ parcIterator_Remove(iterator);
+ result = true;
+ break;
+ }
+ }
+
+ parcIterator_Release(&iterator);
+
+ return result;
+}
+
+static size_t
+_parcSortedList_GetInsertionIndex(const PARCSortedList *instance, const PARCObject *element)
+{
+ ssize_t low = 0;
+ ssize_t high = parcLinkedList_Size(instance->list) - 1;
+
+ if (high == -1) {
+ return 0;
+ }
+
+ while (true) {
+ ssize_t midpoint = (low + (high - low) / 2);
+ PARCObject *e = parcLinkedList_GetAtIndex(instance->list, midpoint);
+ int signum = instance->compare(element, e);
+ if (high == low) {
+ if (signum < 0) {
+ return high;
+ } else if (signum > 0) {
+ return low + 1;
+ } else {
+ return low;
+ }
+ }
+
+ if (signum < 0) {
+ high = midpoint;
+ } else if (signum > 0) {
+ low = midpoint + 1;
+ } else {
+ return midpoint;
+ }
+ }
+
+ return -1;
+}
+
+PARCIterator *
+parcSortedList_CreateIterator(PARCSortedList *instance)
+{
+ return parcLinkedList_CreateIterator(instance->list);
+}
+
+void
+parcSortedList_Add(PARCSortedList *instance, PARCObject *element)
+{
+ size_t insertionPoint = _parcSortedList_GetInsertionIndex(instance, element);
+ assertTrue(insertionPoint >= 0 && insertionPoint <= parcLinkedList_Size(instance->list),
+ "%zd is bad insertion point. Must be >=0 and <= %zd", insertionPoint, parcLinkedList_Size(instance->list));
+
+ parcLinkedList_InsertAtIndex(instance->list, insertionPoint, element);
+}
diff --git a/libparc/parc/algol/parc_SortedList.h b/libparc/parc/algol/parc_SortedList.h
new file mode 100644
index 00000000..393992e7
--- /dev/null
+++ b/libparc/parc/algol/parc_SortedList.h
@@ -0,0 +1,595 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_SortedList.h
+ * @ingroup datastructures
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_SortedList
+#define PARCLibrary_parc_SortedList
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_Iterator.h>
+
+struct PARCSortedList;
+typedef struct PARCSortedList PARCSortedList;
+
+typedef int (*PARCSortedListEntryCompareFunction)(const PARCObject *objA, const PARCObject *objB);
+
+/**
+ * Increase the number of references to a `PARCSortedList` instance.
+ *
+ * Note that new `PARCSortedList` is not created,
+ * only that the given `PARCSortedList` reference count is incremented.
+ * Discard the reference by invoking `parcSortedList_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCSortedList instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * PARCSortedList *b = parcSortedList_Acquire();
+ *
+ * parcSortedList_Release(&a);
+ * parcSortedList_Release(&b);
+ * }
+ * @endcode
+ */
+PARCSortedList *parcSortedList_Acquire(const PARCSortedList *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcSortedList_OptionalAssertValid(_instance_)
+#else
+# define parcSortedList_OptionalAssertValid(_instance_) parcSortedList_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCSortedList` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCSortedList instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * parcSortedList_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcSortedList_Release(&b);
+ * }
+ * @endcode
+ */
+void parcSortedList_AssertValid(const PARCSortedList *instance);
+
+/**
+ * Create an instance of PARCSortedList
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCSortedList instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * parcSortedList_Release(&a);
+ * }
+ * @endcode
+ */
+PARCSortedList *parcSortedList_Create(void);
+
+/**
+ * Create an instance of PARCSortedList and provide a comparison function.
+ *
+ * @param [in] compare A pointer to a function that implements the Compare contract.
+ *
+ * @return non-NULL A pointer to a valid PARCSortedList instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * parcSortedList_Release(&a);
+ * }
+ * @endcode
+ */
+PARCSortedList *parcSortedList_CreateCompare(PARCSortedListEntryCompareFunction compare);
+
+/**
+ * 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 PARCSortedList instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCSortedList` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * PARCSortedList *copy = parcSortedList_Copy(&b);
+ *
+ * parcSortedList_Release(&b);
+ * parcSortedList_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCSortedList *parcSortedList_Copy(const PARCSortedList *original);
+
+/**
+ * Print a human readable representation of the given `PARCSortedList`.
+ *
+ * @param [in] instance A pointer to a valid PARCSortedList instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * parcSortedList_Display(a, 0);
+ *
+ * parcSortedList_Release(&a);
+ * }
+ * @endcode
+ */
+void parcSortedList_Display(const PARCSortedList *instance, int indentation);
+
+/**
+ * Determine if two `PARCSortedList` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCSortedList` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcSortedList_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcSortedList_Equals(x, y)` must return true if and only if
+ * `parcSortedList_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcSortedList_Equals(x, y)` returns true and
+ * `parcSortedList_Equals(y, z)` returns true,
+ * then `parcSortedList_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcSortedList_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcSortedList_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCSortedList instance.
+ * @param [in] y A pointer to a valid PARCSortedList instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ * PARCSortedList *b = parcSortedList_Create();
+ *
+ * if (parcSortedList_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcSortedList_Release(&a);
+ * parcSortedList_Release(&b);
+ * }
+ * @endcode
+ * @see parcSortedList_HashCode
+ */
+bool parcSortedList_Equals(const PARCSortedList *x, const PARCSortedList *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 parcSortedList_Equals} method,
+ * then calling the {@link parcSortedList_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 parcSortedList_Equals} function,
+ * then calling the `parcSortedList_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCSortedList instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * PARCHashCode hashValue = parcSortedList_HashCode(buffer);
+ * parcSortedList_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcSortedList_HashCode(const PARCSortedList *instance);
+
+/**
+ * Determine if an instance of `PARCSortedList` 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 PARCSortedList instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * if (parcSortedList_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcSortedList_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcSortedList_IsValid(const PARCSortedList *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCSortedList` 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
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * parcSortedList_Release(&a);
+ * }
+ * @endcode
+ */
+void parcSortedList_Release(PARCSortedList **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCSortedList 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
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * PARCJSON *json = parcSortedList_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcSortedList_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcSortedList_ToJSON(const PARCSortedList *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCSortedList`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCSortedList 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
+ * {
+ * PARCSortedList *a = parcSortedList_Create();
+ *
+ * char *string = parcSortedList_ToString(a);
+ *
+ * parcSortedList_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcSortedList_Display
+ */
+char *parcSortedList_ToString(const PARCSortedList *instance);
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcSortedList_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] object A pointer to a valid PARCSortedList instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcSortedList_Notify(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotify(parcSortedList, PARCSortedList);
+
+/**
+ * Wakes up all threads that are waiting on the given object's lock.
+ *
+ * A thread waits on an object by calling one of the wait methods, `parcSortedList_Wait`, `parcSortedList_WaitFor`, `parcSortedList_WaitUntil`.
+ * The awakened threads will proceed after the current thread relinquishes the lock on the given object.
+ * The awakened threads will compete in the usual manner with any other threads that might be actively competing
+ * to synchronize on this object.
+ * Awakened threads have no priority between them in being the next thread to lock this object.
+ *
+ * This method can only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid `PARCSortedList` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcSortedList_Lock(object)) {
+ * parcSortedList_NotifyAll(object);
+ * parcSortedList_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotifyAll(parcSortedList, PARCSortedList);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the parcSortedList_Notify() function on the same object.
+ * *
+ * @param [in] object A pointer to a valid `PARCSortedList` instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcSortedList_Wait(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementWait(parcSortedList, PARCSortedList);
+
+parcObject_ImplementWaitFor(parcSortedList, PARCSortedList);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the `parcSortedList_Notify()`
+ * function on the same object or the system time equals or exceeds the specified time.
+ *
+ * The calling thread must own the object's lock.
+ * The calling thread will release ownership of this lock and wait until another thread invokes
+ * `parcSortedList_Notify` or the computer's system time equals or exceeds that specified by @p time.
+ * on the same object.
+ * The original calling thread then re-obtains ownership of the lock and resumes execution.
+ *
+ * This function must only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid PARCSortedList instance.
+ *
+ * @returns false if the alloted time was exceeded.
+ * @returns true if another thread invoked the `parcSortedList_Notify()` or `parcSortedList_NotifyAll()` function
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval tv;
+ * gettimeofday(&tv, NULL);
+ *
+ * struct timespec absoluteTime;
+ * absoluteTime.tv_sec = tv.tv_sec + 0;
+ * absoluteTime.tv_nsec = 0;
+ *
+ * parcSortedList_WaitUntil(object, &absoluteTime);
+ * }
+ * @endcode
+ */
+parcObject_ImplementWaitUntil(parcSortedList, PARCSortedList);
+
+/**
+ * Obtain the lock on the given `PARCSortedList` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] object A pointer to a valid `PARCSortedList` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, or the `PARCSortedList` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcSortedList_Lock(object)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementLock(parcSortedList, PARCSortedList);
+
+/**
+ * Try to obtain the advisory lock on the given PARCSortedList instance.
+ *
+ * Once the lock is obtained, the caller must release the lock as soon as possible.
+ *
+ * @param [in] object A pointer to a valid PARCSortedList instance.
+ *
+ * @return true The PARCSortedList is locked.
+ * @return false The PARCSortedList is unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcSortedList_TryLock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementTryLock(parcSortedList, PARCSortedList);
+
+/**
+ * Try to unlock the advisory lock on the given `PARCSortedList` instance.
+ *
+ * @param [in] object A pointer to a valid `PARCSortedList` instance.
+ *
+ * @return true The `PARCSortedList` was locked and now is unlocked.
+ * @return false The `PARCSortedList` was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcSortedList_Unlock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementUnlock(parcSortedList, PARCSortedList);
+
+/**
+ * Determine if the advisory lock on the given `PARCSortedList` instance is locked.
+ *
+ * @param [in] object A pointer to a valid `PARCSortedList` instance.
+ *
+ * @return true The `PARCSortedList` is locked.
+ * @return false The `PARCSortedList` is unlocked.
+ * Example:
+ * @code
+ * {
+ * if (parcSortedList_IsLocked(object)) {
+ * ...
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementIsLocked(parcSortedList, PARCSortedList);
+
+PARCIterator *parcSortedList_CreateIterator(PARCSortedList *instance);
+
+void parcSortedList_Add(PARCSortedList *instance, PARCObject *element);
+
+size_t parcSortedList_Size(const PARCSortedList *list);
+
+PARCObject *parcSortedList_GetAtIndex(const PARCSortedList *list, const size_t index);
+
+/**
+ * Return the first element of the specified list.
+ * The element's reference count is not modified,
+ * the caller must acquire its own reference to the element if it is needed beyond lifetime of the given list.
+ *
+ * @param [in] list A pointer to the instance of `PARCSortedList` from which the first element will be returned.
+ *
+ * @return non NULL A pointer to the element
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCObject *parcSortedList_GetFirst(const PARCSortedList *list);
+
+/**
+ * Return the last element of the specified list.
+ * The element's reference count is not modified,
+ * the caller must acquire its own reference to the element if it is needed beyond lifetime of the given list.
+ *
+ * @param [in] list A pointer to the instance of `PARCSortedList` from which the last element will be returned.
+ *
+ * @return non NULL A pointer to the element
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCObject *parcSortedList_GetLast(const PARCSortedList *list);
+
+
+bool parcSortedList_Remove(PARCSortedList *list, const PARCObject *object);
+/**
+ * Return the first element of the specified list and remove it from the list.
+ * The element's reference count is not modified,
+ * the caller must release the returned element when it is finished with it.
+ *
+ * @param [in] list A pointer to the instance of `PARCSortedList` from which the first element will be returned and removed
+ *
+ * @return non NULL A pointer to the element removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCObject *parcSortedList_RemoveFirst(PARCSortedList *list);
+
+/**
+ * Return the last element of the specified list and remove it from the list.
+ * The element's reference count is not modified,
+ * the caller must release the returned element when it is finished with it.
+ *
+ * @param [in] list A pointer to the instance of `PARCSortedList` from which the last element will be removed and returned.
+ *
+ * @return non-NULL A pointer to the element removed
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCObject *parcSortedList_RemoveLast(PARCSortedList *list);
+
+#endif
diff --git a/libparc/parc/algol/parc_Stack.c b/libparc/parc/algol/parc_Stack.c
new file mode 100755
index 00000000..5930169b
--- /dev/null
+++ b/libparc/parc/algol/parc_Stack.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Deque.h>
+#include <parc/algol/parc_Stack.h>
+
+struct parc_stack {
+ void *instance;
+ PARCStackInterface *interface;
+};
+
+PARCStack *
+parcStack(void *instance, PARCStackInterface *interface)
+{
+ PARCStack *result = parcMemory_AllocateAndClear(sizeof(PARCStack));
+ assertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCStack));
+ result->instance = instance;
+ result->interface = interface;
+
+ return result;
+}
+
+void
+parcStack_Release(PARCStack **stackPtr)
+{
+ PARCStack *stack = *stackPtr;
+ (stack->interface->parcStack_Release)(&stack->instance);
+ parcMemory_Deallocate((void **) &stack);
+
+ *stackPtr = 0;
+}
+
+bool
+parcStack_IsEmpty(const PARCStack *stack)
+{
+ return (stack->interface->parcStack_IsEmpty)(stack->instance);
+}
+
+void *
+parcStack_Peek(const PARCStack *stack)
+{
+ return (stack->interface->parcStack_Peek)(stack->instance);
+}
+
+void *
+parcStack_Pop(PARCStack *stack)
+{
+ return (stack->interface->parcStack_Pop)(stack->instance);
+}
+
+void *
+parcStack_Push(PARCStack *stack, void *element)
+{
+ return (stack->interface->parcStack_Push)(stack->instance, element);
+}
diff --git a/libparc/parc/algol/parc_Stack.h b/libparc/parc/algol/parc_Stack.h
new file mode 100755
index 00000000..e64e02f4
--- /dev/null
+++ b/libparc/parc/algol/parc_Stack.h
@@ -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.
+ */
+
+/**
+ * @file parc_Stack.h
+ * @ingroup datastructures
+ * @brief PARC (Generic) Stack
+ *
+ * A stack interface implementation.
+ *
+ * Example
+ * @code
+ * #include <parc/algol/parc_Deque.h>
+ *
+ * int
+ * main(int argc, char *argv[])
+ * {
+ * PARCStackInterface dequeAsStack = {
+ * .parcStack_Release = parcDeque_Release,
+ * .parcStack_IsEmpty = parcDeque_IsEmpty,
+ * .parcStack_Peek = parcDeque_PeekLast,
+ * .parcStack_Pop = parcDeque_RemoveLast,
+ * .parcStack_Push = parcDeque_Append,
+ * .parcStack_Search = NULL
+ * };
+ *
+ * PARCStack *stack = parcStack(parcDeque_Create(), &dequeAsStack);
+ *
+ * parcStack_IsEmpty(stack);
+ * }
+ * @endcode
+ *
+ *
+ */
+#ifndef libparc_parc_Stack_h
+#define libparc_parc_Stack_h
+
+#include <stdbool.h>
+
+struct parc_stack;
+typedef struct parc_stack PARCStack;
+
+typedef struct parc_stack_interface {
+ /**
+ * Release the instance
+ *
+ *
+ * @param [in,out] instancePtr A pointer to the pointer of the instance to release.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ void (*parcStack_Release)(void **instancePtr);
+
+ /**
+ * Tests if this stack is empty.
+ *
+ * @param [in] instance A pointer to the instance to test.
+ * @return true if the stack is empty
+ * @return false if the stack is not empty
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ bool (*parcStack_IsEmpty)(const void *instance);
+
+ /**
+ * Looks at the object at the top of this stack without removing it from the stack.
+ *
+ * @param [in] instance A pointer to the instance to look at.
+ * @return The object at the top of the @p instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ void * (*parcStack_Peek)(const void *instance);
+
+ /**
+ * Removes the object at the top of this stack and returns that object as the value of this function.
+ *
+ *
+ * @param [in,out] instance A pointer to the instance to check and modify.
+ * @return The object at the top of the @p instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ void * (*parcStack_Pop)(void *instance);
+
+ /**
+ * Pushes an item onto the top of this stack.
+ *
+ *
+ * @param [in,out] instance A pointer to the instance to modify.
+ * @param [in] item A pointer to the object to push on the @p instance.
+ * @return A pointer to the object that was pushed on the @p instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ void * (*parcStack_Push)(void *instance, void *item);
+
+ /**
+ * Returns the 1-based position where an object is on this stack.
+ *
+ *
+ * @param [in] instance A pointer to the instance.
+ * @param [in] element A pointer to the element to find on the @p instance.
+ * @return The index of the position where @p element is found in the @p instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ int (*parcStack_Search)(void *instance, void *element);
+} PARCStackInterface;
+#endif // libparc_parc_Stack_h
diff --git a/libparc/parc/algol/parc_StandardOutputStream.c b/libparc/parc/algol/parc_StandardOutputStream.c
new file mode 100644
index 00000000..0c46ce3c
--- /dev/null
+++ b/libparc/parc/algol/parc_StandardOutputStream.c
@@ -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.
+ */
+
+/**
+ */
+#include <parc/algol/parc_StandardOutputStream.h>
+#include <parc/algol/parc_OutputStream.h>
+#include <parc/algol/parc_Object.h>
+
+struct PARCStandardOutputStream {
+ int fd;
+};
+
+static struct PARCOutputStreamImplementation _implementation = {
+ .Write = PARCStandardOutputStream_Write,
+ .Acquire = PARCStandardOutputStream_Acquire,
+ .Release = PARCStandardOutputStream_Release;
+};
+
+static void
+_parcStandardOutputStream_Destroy(PARCStandardOutputStream **streamPtr)
+{
+ parcObject_Release((void **) streamPtr);
+}
+
+static const PARCObjectImpl _parcStandardOutputStream_Object = {
+ .destroy = (PARCObjectDestroy *) _parcStandardOutputStream_Destroy,
+ .copy = NULL,
+ .toString = NULL,
+ .equals = NULL,
+ .compare = NULL
+};
+
+PARCOutputStream *
+parcStandardOutputStream(void)
+{
+ PARCStandardOutputStream *instance = PARCStandardOutputStream_Create();
+ parcOutputStream(instance, &_implementation)
+}
+
+PARCStandardOutputStream *
+PARCStandardOutputStream_Create(void)
+{
+ parcObject_Create(sizeof(PARCStandardOutputStream), &_parcStandardOutputStream_Object);
+ return NULL;
+}
+
+PARCStandardOutputStream *
+PARCStandardOutputStream_Acquire(PARCStandardOutputStream *instance)
+{
+ return parcObject_Acquire(instance);
+}
+
+void
+PARCStandardOutputStream_Release(PARCStandardOutputStream **instanceP)
+{
+ parcObject_Release((void **) instanceP);
+}
+
+bool
+parcFileOutputStream_Write(PARCStandardOutputStream *stream, PARCBuffer *buffer)
+{
+ return false;
+}
diff --git a/libparc/parc/algol/parc_StandardOutputStream.h b/libparc/parc/algol/parc_StandardOutputStream.h
new file mode 100644
index 00000000..be5a21d3
--- /dev/null
+++ b/libparc/parc/algol/parc_StandardOutputStream.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 parc_StandardOutputStream.h
+ * @brief Standard output stream structures and functions.
+ *
+ */
+
+#ifndef __PARC_Library__parc_StandardOutputStream__
+#define __PARC_Library__parc_StandardOutputStream__
+
+struct PARCStandardOutputStream;
+typedef struct PARCStandardOutputStream PARCStandardOutputStream;
+
+#include <parc/algol/parc_OutputStream.h>
+
+PARCOutputStream *parcStandardOutputStream(void);
+
+PARCStandardOutputStream *PARCStandardOutputStream_Create(void);
+
+PARCStandardOutputStream *PARCStandardOutputStream_Acquire(PARCStandardOutputStream *instance);
+
+void PARCStandardOutputStream_Release(PARCStandardOutputStream **instanceP);
+
+#endif /* defined(__PARC_Library__parc_StandardOutputStream__) */
diff --git a/libparc/parc/algol/parc_StdlibMemory.c b/libparc/parc/algol/parc_StdlibMemory.c
new file mode 100755
index 00000000..a919f727
--- /dev/null
+++ b/libparc/parc/algol/parc_StdlibMemory.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 <stdio.h>
+#include <stdlib.h>
+#include <sys/errno.h>
+#include <stdbool.h>
+#include <string.h>
+#include <strings.h>
+#include <pthread.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_StdlibMemory.h>
+
+static uint32_t _parcStdlibMemory_OutstandingAllocations;
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+static pthread_mutex_t _parcStdlibMemory_Mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static inline void
+_parcStdlibMemory_IncrementOutstandingAllocations(void)
+{
+ pthread_mutex_lock(&_parcStdlibMemory_Mutex);
+ _parcStdlibMemory_OutstandingAllocations++;
+ pthread_mutex_unlock(&_parcStdlibMemory_Mutex);
+}
+
+static inline void
+_parcStdlibMemory_DecrementOutstandingAllocations(void)
+{
+ pthread_mutex_lock(&_parcStdlibMemory_Mutex);
+ _parcStdlibMemory_OutstandingAllocations--;
+ pthread_mutex_unlock(&_parcStdlibMemory_Mutex);
+}
+#else
+
+static inline void
+_parcStdlibMemory_IncrementOutstandingAllocations(void)
+{
+ __sync_add_and_fetch(&_parcStdlibMemory_OutstandingAllocations, 1);
+}
+
+static inline void
+_parcStdlibMemory_DecrementOutstandingAllocations(void)
+{
+ __sync_sub_and_fetch(&_parcStdlibMemory_OutstandingAllocations, 1);
+}
+#endif
+
+#ifndef HAVE_REALLOC
+static void *
+_parcStdlibMemory_rplRealloc(void *oldAlloc, size_t newSize)
+{
+ if (newSize == 0) {
+ newSize = 1;
+ }
+
+ char *newAlloc = malloc(newSize);
+
+ if (oldAlloc != NULL) {
+ memcpy(newAlloc, oldAlloc, newSize);
+ free(oldAlloc);
+ }
+ return newAlloc;
+}
+#endif
+
+void *
+parcStdlibMemory_Allocate(size_t size)
+{
+ if (size == 0) {
+ return NULL;
+ }
+
+ void *result = malloc(size);
+ if (result != NULL) {
+ _parcStdlibMemory_IncrementOutstandingAllocations();
+ }
+
+ return result;
+}
+
+void *
+parcStdlibMemory_AllocateAndClear(size_t size)
+{
+ void *pointer = parcStdlibMemory_Allocate(size);
+ if (pointer != NULL) {
+ memset(pointer, 0, size);
+ }
+ return pointer;
+}
+
+int
+parcStdlibMemory_MemAlign(void **pointer, size_t alignment, size_t size)
+{
+ if (size == 0) {
+ return EINVAL;
+ }
+
+ int failure = posix_memalign(pointer, alignment, size);
+
+ if (failure != 0) {
+ return failure;
+ }
+ if (*pointer == NULL) {
+ return ENOMEM;
+ }
+
+ _parcStdlibMemory_IncrementOutstandingAllocations();
+
+ return 0;
+}
+
+void
+parcStdlibMemory_Deallocate(void **pointer)
+{
+#ifndef PARCLibrary_DISABLE_VALIDATION
+ trapIllegalValueIf(_parcStdlibMemory_OutstandingAllocations == 0,
+ "parcStdlibMemory_Deallocate invoked with nothing left to free (double free somewhere?)\n");
+#endif
+ free(*pointer);
+ *pointer = NULL;
+
+ _parcStdlibMemory_DecrementOutstandingAllocations();
+}
+
+void *
+parcStdlibMemory_Reallocate(void *pointer, size_t newSize)
+{
+#ifdef HAVE_REALLOC
+ void *result = realloc(pointer, newSize);
+#else
+ void *result = _parcStdlibMemory_rplRealloc(pointer, newSize);
+#endif
+
+ if (pointer == NULL) {
+ _parcStdlibMemory_IncrementOutstandingAllocations();
+ }
+ return result;
+}
+
+char *
+parcStdlibMemory_StringDuplicate(const char *string, size_t length)
+{
+ _parcStdlibMemory_IncrementOutstandingAllocations();
+ return strndup(string, length);
+}
+
+uint32_t
+parcStdlibMemory_Outstanding(void)
+{
+ return _parcStdlibMemory_OutstandingAllocations;
+}
+
+PARCMemoryInterface PARCStdlibMemoryAsPARCMemory = {
+ .Allocate = (uintptr_t) parcStdlibMemory_Allocate,
+ .AllocateAndClear = (uintptr_t) parcStdlibMemory_AllocateAndClear,
+ .MemAlign = (uintptr_t) parcStdlibMemory_MemAlign,
+ .Deallocate = (uintptr_t) parcStdlibMemory_Deallocate,
+ .Reallocate = (uintptr_t) parcStdlibMemory_Reallocate,
+ .StringDuplicate = (uintptr_t) parcStdlibMemory_StringDuplicate,
+ .Outstanding = (uintptr_t) parcStdlibMemory_Outstanding
+};
diff --git a/libparc/parc/algol/parc_StdlibMemory.h b/libparc/parc/algol/parc_StdlibMemory.h
new file mode 100755
index 00000000..9abbf915
--- /dev/null
+++ b/libparc/parc/algol/parc_StdlibMemory.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_StdlibMemory.h
+ * @ingroup datastructures
+ *
+ * @brief Standard library memory mangement functions wrapped up to be suitable for use by parc_Memory.[ch]
+ *
+ */
+#ifndef libparc_parc_StdlibMemory_h
+#define libparc_parc_StdlibMemory_h
+
+#include <parc/algol/parc_Memory.h>
+
+extern PARCMemoryInterface PARCStdlibMemoryAsPARCMemory;
+
+/**
+ * Allocate memory.
+ *
+ * @param [in] size The size of memory to allocate
+ *
+ * @return A pointer to the allocated memory.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcStdlibMemory_Allocate(size_t size);
+
+/**
+ * Allocate memory of size @p size and clear it.
+ *
+ * @param [in] size Size of memory to allocate
+ *
+ * @return A pointer to the allocated memory
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcStdlibMemory_AllocateAndClear(size_t size);
+
+/**
+ * Allocate aligned memory.
+ *
+ * Allocates @p size bytes of memory such that the allocation's
+ * base address is an exact multiple of alignment,
+ * and returns the allocation in the value pointed to by @p pointer.
+ *
+ * The requested alignment must be a power of 2 greater than or equal to `sizeof(void *)`.
+ *
+ * Memory that is allocated can be used as an argument in subsequent call `Reallocate`, however
+ * `Reallocate` is not guaranteed to preserve the original alignment.
+ *
+ * @param [out] pointer A pointer to a `void *` pointer that will be set to the address of the allocated memory.
+ * @param [in] alignment A power of 2 greater than or equal to `sizeof(void *)`
+ * @param [in] size The number of bytes to allocate.
+ *
+ * @return 0 Successful
+ * @return EINVAL The alignment parameter is not a power of 2 at least as large as sizeof(void *)
+ * @return ENOMEM Memory allocation error.
+ *
+ * Example:
+ * @code
+ * {
+ * void *allocatedMemory;
+ *
+ * int failure = parcStdlibMemory_MemAlign(&allocatedMemory, sizeof(void *), 100);
+ * if (failure == 0) {
+ * parcStdlibMemory_Deallocate(&allocatedMemory);
+ * // allocatedMemory is now equal to zero.
+ * }
+ * }
+ * @endcode
+ * @see {@link parcMemory_MemAlign}
+ */
+int parcStdlibMemory_MemAlign(void **pointer, size_t alignment, size_t size);
+
+/**
+ * Deallocate the memory pointed to by @p pointer
+ *
+ * @param [in,out] pointer A pointer to a pointer to the memory to be deallocated
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcStdlibMemory_Deallocate(void **pointer);
+
+/**
+ * Resizes previously allocated memory at @p pointer to @p newSize. If necessary,
+ * new memory is allocated and the content copied from the old memory to the
+ * new memory and the old memory is deallocated.
+ *
+ * @param [in,out] pointer A pointer to the memory to be reallocated.
+ * @param [in] newSize The size that the memory to be resized to.
+ *
+ * @return A pointer to the memory
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcStdlibMemory_Reallocate(void *pointer, size_t newSize);
+
+/**
+ * Allocate sufficient memory for a copy of the string @p string,
+ * copy at most n characters from the string @p string into the allocated memory,
+ * and return the pointer to allocated memory.
+ *
+ * The copied string is always null-terminated.
+ *
+ * @param [in] string A pointer to a null-terminated string.
+ * @param [in] length The maximum allowed length of the resulting copy.
+ *
+ * @return non-NULL A pointer to allocated memory.
+ * @return NULL A an error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * char *string = "this is a string";
+ * char *copy = parcStdlibMemory_StringDuplicate(string, strlen(string));
+ *
+ * if (copy != NULL) {
+ * . . .
+ * parcStdLibMemory_Deallocate(&copy);
+ * }
+ * }
+ * @endcode
+ *
+ * @see {@link parcStdlibMemory_Deallocate()}
+ */
+char *parcStdlibMemory_StringDuplicate(const char *string, size_t length);
+
+/**
+ * Return the number of outstanding allocations managed by this allocator.
+ *
+ * When you allocate memory, this count goes up by one. When you deallocate, it goes down by one.
+ * A well-behaved program will terminate with a call to `parcStdlibMemory_Outstanding()` returning 0.
+ *
+ * @return The number of memory allocations still outstanding (remaining to be deallocated).
+ *
+ * Example:
+ * @code
+ * {
+ * uint32_t numberOfAllocations = parcStdlibMemory_Outstanding();
+ * }
+ * @endcode
+ */
+uint32_t parcStdlibMemory_Outstanding(void);
+
+
+/**
+ * Replacement function for realloc(3).
+ *
+ * The standard `realloc()` function tries to change the size of the allocation pointed to by @p oldAlloc to @p newSize,
+ * and returns @p oldAlloc. If there is not enough room to enlarge the memory allocation pointed to by @p oldAlloc,
+ * realloc() creates a new allocation, copies as much of the old data pointed to by @p oldAlloc as will fit to the new allocation,
+ * frees the old allocation, and returns a pointer to the allocated memory.
+ *
+ * If @p oldAlloc is `NULL`, `realloc()` is identical to a call to `malloc()` for size bytes.
+ * If @p newSize is zero and @p oldAlloc is not NULL, a new, minimum sized object is allocated and the original object is freed.
+ * When extending a region allocated with `calloc(3)`, `realloc(3)` does not guarantee that the additional memory
+ * is also zero-filled.
+ *
+ * If the realloc(3) function is not compatible with the above constraints
+ * (i.e., ‘realloc(NULL, 0)’ returns an invalid pointer), then autoconf tools will define
+ * `realloc` to `rpl_realloc` so that the native realloc is not used in the main project.
+ *
+ * @param [in] oldAlloc A previously allocated
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void *rpl_realloc(void *oldAlloc, size_t newSize);
+#endif // libparc_parc_StdlibMemory_h
diff --git a/libparc/parc/algol/parc_String.c b/libparc/parc/algol/parc_String.c
new file mode 100755
index 00000000..e5af5f71
--- /dev/null
+++ b/libparc/parc/algol/parc_String.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 <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/algol/parc_String.h>
+
+struct PARCString {
+ char *string;
+};
+
+static bool
+_parcString_Destructor(PARCString **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCString pointer.");
+ PARCString *string = *instancePtr;
+
+ parcMemory_Deallocate(&string->string);
+ return true;
+}
+
+parcObject_ImplementAcquire(parcString, PARCString);
+
+parcObject_ImplementRelease(parcString, PARCString);
+
+parcObject_Override(PARCString, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcString_Destructor,
+ .copy = (PARCObjectCopy *) parcString_Copy,
+ .display = (PARCObjectDisplay *) parcString_Display,
+ .toString = (PARCObjectToString *) parcString_ToString,
+ .equals = (PARCObjectEquals *) parcString_Equals,
+ .compare = (PARCObjectCompare *) parcString_Compare,
+ .hashCode = (PARCObjectHashCode *) parcString_HashCode,
+ .toJSON = (PARCObjectToJSON *) parcString_ToJSON,
+ .display = (PARCObjectDisplay *) parcString_Display);
+
+void
+parcString_AssertValid(const PARCString *instance)
+{
+ assertTrue(parcString_IsValid(instance),
+ "PARCString is not valid.");
+}
+
+PARCString *
+parcString_Create(const char *string)
+{
+ PARCString *result = parcObject_CreateInstance(PARCString);
+ if (result != NULL) {
+ result->string = parcMemory_StringDuplicate(string, strlen(string));
+ }
+ return result;
+}
+
+PARCString *
+parcString_CreateFromBuffer(const PARCBuffer *buffer)
+{
+ PARCString *result = parcString_Create(parcBuffer_Overlay((PARCBuffer *) buffer, 0));
+
+ return result;
+}
+
+int
+parcString_Compare(const PARCString *string, const PARCString *other)
+{
+ int result = 0;
+
+ if (string == NULL) {
+ if (other != NULL) {
+ result = -1;
+ }
+ } else if (other == NULL) {
+ result = 1;
+ } else {
+ parcString_OptionalAssertValid(string);
+ parcString_OptionalAssertValid(other);
+
+ int comparison = strcmp(string->string, other->string);
+ if (comparison < 0) {
+ result = -1;
+ } else if (comparison > 0) {
+ result = 1;
+ }
+ }
+
+ return result;
+}
+
+PARCString *
+parcString_Copy(const PARCString *original)
+{
+ PARCString *result = parcString_Create(original->string);
+
+ return result;
+}
+
+void
+parcString_Display(const PARCString *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCString@%p {", instance);
+ parcDisplayIndented_PrintLine(indentation + 1, "%s", instance->string);
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcString_Equals(const PARCString *x, const PARCString *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ parcString_OptionalAssertValid(x);
+ parcString_OptionalAssertValid(y);
+
+ result = strcmp(x->string, y->string) == 0;
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcString_HashCode(const PARCString *string)
+{
+ PARCHashCode result = 0;
+
+ result = parcHashCode_Hash((uint8_t *) string->string, strlen(string->string));
+
+ return result;
+}
+
+bool
+parcString_IsValid(const PARCString *string)
+{
+ bool result = false;
+
+ if (string != NULL) {
+ if (string->string != NULL) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcString_ToJSON(const PARCString *string)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ return result;
+}
+
+char *
+parcString_ToString(const PARCString *string)
+{
+ char *result = parcMemory_StringDuplicate(string->string, strlen(string->string));
+
+ return result;
+}
+
+const char *
+parcString_GetString(const PARCString *string)
+{
+ parcString_OptionalAssertValid(string);
+
+ return string->string;
+}
diff --git a/libparc/parc/algol/parc_String.h b/libparc/parc/algol/parc_String.h
new file mode 100644
index 00000000..4fe4307f
--- /dev/null
+++ b/libparc/parc/algol/parc_String.h
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_String.h
+ * @ingroup types
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_String
+#define PARCLibrary_parc_String
+#include <stdbool.h>
+#include <string.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+typedef struct PARCString PARCString;
+extern parcObjectDescriptor_Declaration(PARCString);
+
+/**
+ * Increase the number of references to a `PARCString` instance.
+ *
+ * Note that new `PARCString` is not created,
+ * only that the given `PARCString` reference count is incremented.
+ * Discard the reference by invoking `parcString_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCString instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * PARCString *b = parcString_Acquire();
+ *
+ * parcString_Release(&a);
+ * parcString_Release(&b);
+ * }
+ * @endcode
+ */
+PARCString *parcString_Acquire(const PARCString *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcString_OptionalAssertValid(_instance_)
+#else
+# define parcString_OptionalAssertValid(_instance_) parcString_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCString` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCString instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * parcString_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcString_Release(&b);
+ * }
+ * @endcode
+ */
+void parcString_AssertValid(const PARCString *instance);
+
+/**
+ * Create an instance of PARCString
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCString instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * parcString_Release(&a);
+ * }
+ * @endcode
+ */
+PARCString *parcString_Create(const char *);
+
+/**
+ * Create an instance of PARCString from the content of a given PARCBuffer.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCString instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * parcString_Release(&a);
+ * }
+ * @endcode
+ */
+PARCString *parcString_CreateFromBuffer(const PARCBuffer *buffer);
+
+/**
+ * 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 PARCString instance.
+ * @param [in] other A pointer to a valid PARCString 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
+ * {
+ * PARCString *a = parcString_Create();
+ * PARCString *b = parcString_Create();
+ *
+ * if (parcString_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcString_Release(&a);
+ * parcString_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcString_Equals
+ */
+int parcString_Compare(const PARCString *instance, const PARCString *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 PARCString instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCString` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * PARCString *copy = parcString_Copy(&b);
+ *
+ * parcString_Release(&b);
+ * parcString_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCString *parcString_Copy(const PARCString *original);
+
+/**
+ * Print a human readable representation of the given `PARCString`.
+ *
+ * @param [in] instance A pointer to a valid PARCString instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * parcString_Display(a, 0);
+ *
+ * parcString_Release(&a);
+ * }
+ * @endcode
+ */
+void parcString_Display(const PARCString *instance, int indentation);
+
+/**
+ * Determine if two `PARCString` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCString` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcString_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcString_Equals(x, y)` must return true if and only if
+ * `parcString_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcString_Equals(x, y)` returns true and
+ * `parcString_Equals(y, z)` returns true,
+ * then `parcString_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcString_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcString_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCString instance.
+ * @param [in] y A pointer to a valid PARCString instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ * PARCString *b = parcString_Create();
+ *
+ * if (parcString_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcString_Release(&a);
+ * parcString_Release(&b);
+ * }
+ * @endcode
+ * @see parcString_HashCode
+ */
+bool parcString_Equals(const PARCString *x, const PARCString *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 parcString_Equals} method,
+ * then calling the {@link parcString_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 parcString_Equals} function,
+ * then calling the `parcString_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCString instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * PARCHashCode hashValue = parcString_HashCode(buffer);
+ * parcString_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcString_HashCode(const PARCString *instance);
+
+/**
+ * Determine if an instance of `PARCString` 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 PARCString instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * if (parcString_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcString_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcString_IsValid(const PARCString *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCString` 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
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * parcString_Release(&a);
+ * }
+ * @endcode
+ */
+void parcString_Release(PARCString **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCString 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
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * PARCJSON *json = parcString_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcString_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcString_ToJSON(const PARCString *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCString`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCString 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
+ * {
+ * PARCString *a = parcString_Create();
+ *
+ * char *string = parcString_ToString(a);
+ *
+ * parcString_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcString_Display
+ */
+char *parcString_ToString(const PARCString *instance);
+
+/**
+ * Get a pointer to the underlying nul-terminated sequence of bytes containing the string's value.
+ *
+ * @param [in] string A pointer to a valid PARCString instance.
+ *
+ * @return A pointer to the underlying nul-terminated sequence of bytes
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+const char *parcString_GetString(const PARCString *string);
+#endif
diff --git a/libparc/parc/algol/parc_Time.c b/libparc/parc/algol/parc_Time.c
new file mode 100755
index 00000000..7cc358b9
--- /dev/null
+++ b/libparc/parc/algol/parc_Time.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 <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Time.h>
+#include <parc/algol/parc_Memory.h>
+
+char *
+parcTime_TimevalAsString(struct timeval timeval)
+{
+ char *string;
+ int nwritten = asprintf(&string, "%ld.%06ld", timeval.tv_sec, (long) timeval.tv_usec);
+ assertTrue(nwritten >= 0, "Error calling asprintf");
+
+ char *result = parcMemory_StringDuplicate(string, strlen(string));
+ free(string);
+ return result;
+}
+
+char *
+parcTime_TimevalAsRFC3339(const struct timeval *utcTime, char result[64])
+{
+ char tmbuf[64];
+ struct tm theTime;
+
+ struct tm *nowtm = gmtime_r(&utcTime->tv_sec, &theTime);
+ strftime(tmbuf, sizeof tmbuf, "%Y-%m-%dT%H:%M:%S", nowtm);
+ snprintf(result, 64, "%s.%06ldZ", tmbuf, (long) utcTime->tv_usec);
+ return result;
+}
+
+char *
+parcTime_TimevalAsISO8601(const struct timeval *utcTime, char result[64])
+{
+ char tmbuf[64];
+ struct tm theTime;
+
+ struct tm *nowtm = gmtime_r(&utcTime->tv_sec, &theTime);
+ strftime(tmbuf, sizeof tmbuf, "%Y-%m-%d %H:%M:%S", nowtm);
+ snprintf(result, 64, "%s.%06ldZ", tmbuf, (long) utcTime->tv_usec);
+ return result;
+}
+
+char *
+parcTime_TimeAsRFC3339(const time_t utcTime, char result[64])
+{
+ struct timeval theTime = { utcTime, 0 };
+
+ return parcTime_TimevalAsRFC3339(&theTime, result);
+}
+
+char *
+parcTime_NowAsRFC3339(char result[64])
+{
+ struct timeval theTime;
+ gettimeofday(&theTime, NULL);
+
+ return parcTime_TimevalAsRFC3339(&theTime, result);
+}
+
+char *
+parcTime_TimeAsISO8601(const time_t utcTime, char result[64])
+{
+ struct timeval theTime = { utcTime, 0 };
+
+ return parcTime_TimevalAsISO8601(&theTime, result);
+}
+
+char *
+parcTime_NowAsISO8601(char result[64])
+{
+ struct timeval theTime;
+ gettimeofday(&theTime, NULL);
+
+ return parcTime_TimevalAsISO8601(&theTime, result);
+}
+
+struct timeval
+parcTime_TimevalAdd(const struct timeval *addend1, const struct timeval *addend2)
+{
+ struct timeval sum;
+
+ sum.tv_sec = addend1->tv_sec + addend2->tv_sec;
+ sum.tv_usec = addend1->tv_usec + addend2->tv_usec;
+ if (sum.tv_usec >= 1000000) {
+ sum.tv_usec -= 1000000;
+ sum.tv_sec++;
+ }
+ return sum;
+}
+
+struct timeval
+parcTime_TimevalSubtract(const struct timeval *minuend, const struct timeval *subtrahend)
+{
+ struct timeval result;
+
+ result.tv_sec = minuend->tv_sec - subtrahend->tv_sec;
+ result.tv_usec = minuend->tv_usec - subtrahend->tv_usec;
+ if (result.tv_usec < 0) {
+ result.tv_sec--;
+ result.tv_usec += 1000000;
+ }
+ return result;
+}
+
+struct timeval
+parcTime_NowTimeval(void)
+{
+ struct timeval timeval;
+ gettimeofday(&timeval, NULL);
+ return timeval;
+}
+
+uint64_t
+parcTime_NowMicroseconds(void)
+{
+ struct timeval timeval;
+ gettimeofday(&timeval, NULL);
+
+ uint64_t result = timeval.tv_sec * 1000000 + timeval.tv_usec;
+ return result;
+}
+
+uint64_t
+parcTime_NowNanoseconds(void)
+{
+ struct timeval timeval;
+ gettimeofday(&timeval, NULL);
+
+ uint64_t result = timeval.tv_sec * 1000000000 + timeval.tv_usec * 1000;
+ return result;
+}
diff --git a/libparc/parc/algol/parc_Time.h b/libparc/parc/algol/parc_Time.h
new file mode 100644
index 00000000..2a68144e
--- /dev/null
+++ b/libparc/parc/algol/parc_Time.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 parc_Time.h
+ * @ingroup inputoutput
+ * @brief Time Manipulation
+ *
+ * Different platforms have different ways to express time-of-day, elapsed-time, clock-time.
+ * In some cases multiple ways to express the same semantic value have evolved over time,
+ * for example `struct timeval` and `struct timespec`.
+ *
+ */
+#ifndef libparc_parc_Time_h
+#define libparc_parc_Time_h
+
+#include <sys/time.h>
+#include <stdint.h>
+
+/**
+ * Create a nul-terminated C string containing the formatted representation of a `struct timeval`.
+ *
+ * The minimum length of the result is 8 characters consisting of the `struct timeval`
+ * formatted as a decimal string consisting of the number of seconds since midnight (0 hour), January 1, 1970.
+ *
+ * @param [in] timeval The instance of the struct `timeval` to convert to a C string.
+ * @return An allocated, null-terminated C string that must be freed via {@link parcMemory_Deallocate()}.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval timeval;
+ * gettimeofday(&timeval, NULL);
+ *
+ * char *string = parcTime_TimevalAsString(timeval);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ */
+char *parcTime_TimevalAsString(struct timeval timeval);
+
+/**
+ * Format an ISO8601 date from the given struct timeval into the given character array, @p result.
+ *
+ * @param [in] utcTime A pointer to a valid struct timeval instance with the time in UTC.
+ * @param [out] result A pointer to the 64 element nul-terminated character array, @p result.
+ *
+ * @return The same value as @p result.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval theTime;
+ * gettimeofday(&theTime, NULL);
+ *
+ * char result[64];
+ * parcTime_TimevalAsISO8601(&theTime, result);
+ *
+ * }
+ * @endcode
+ */
+char *parcTime_TimevalAsISO8601(const struct timeval *utcTime, char *result);
+
+/**
+ * Format an RFC3339 compliant date from the given struct timeval into the given character array.
+ *
+ * @param [in] utcTime A pointer to a valid struct timeval instance with the time in UTC.
+ * @param [out] result A pointer to the 64 element nul-terminated character array, @p result.
+ *
+ * @return The same value as @p result.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval theTime;
+ * gettimeofday(&theTime, NULL);
+ *
+ * char result[64];
+ * parcTime_TimevalAsRFC3339(&theTime, result);
+ *
+ * }
+ * @endcode
+ */
+char *parcTime_TimevalAsRFC3339(const struct timeval *utcTime, char *result);
+
+/**
+ * Format an ISO8601 date from the given `time_t` value into the given character array, @p result.
+ *
+ * @param [in] utcTime `time_t` value representing the time in UTC.
+ * @param [out] result A pointer to the 64 element nul-terminated character array, @p result.
+ *
+ * @return The same value as @p result.
+ *
+ * Example:
+ * @code
+ * {
+ * time_t theTime = time(0);
+ *
+ * char result[64];
+ * parcTime_TimeAsISO8601(theTime, result);
+ *
+ * }
+ * @endcode
+ */
+char *parcTime_TimeAsISO8601(const time_t utcTime, char *result);
+
+/**
+ * Format the current time as an ISO8601 date into the given character array, @p result.
+ *
+ * @param [out] result A pointer to the 64 element nul-terminated character array, @p result.
+ *
+ * @return The same value as @p result.
+ *
+ * Example:
+ * @code
+ * {
+ * char result[64];
+ * parcTime_NowAsISO8601(theTime, result);
+ *
+ * }
+ * @endcode
+ */
+char *parcTime_NowAsISO8601(char *result);
+
+/**
+ * Format an RFC3339 compliant date from the given `time_t` value into the given character array.
+ *
+ * @param [in] utcTime `time_t` value of the time in UTC.
+ * @param [out] result A pointer to the 64 element nul-terminated character array, @p result.
+ *
+ * @return The same value as @p result.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval theTime;
+ * time_t theTime = time(0);
+ *
+ * char result[64];
+ * parcTime_TimeAsRFC3339(&theTime, result);
+ *
+ * }
+ * @endcode
+ */
+char *parcTime_TimeAsRFC3339(const time_t utcTime, char *result);
+
+/**
+ * Format the current time as an RFC3339 compliant date into the given character array.
+ *
+ * @param [out] result A pointer to the 64 element nul-terminated character array, @p result.
+ *
+ * @return The same value as @p result.
+ *
+ * Example:
+ * @code
+ * {
+ * char result[64];
+ * parcTime_NowAsRFC3339(&theTime, result);
+ *
+ * }
+ * @endcode
+ */
+char *parcTime_NowAsRFC3339(char *result);
+
+/**
+ * Add two `struct timeval` values together.
+ *
+ * @param [in] addend1 The first value.
+ * @param [in] addend2 The second value.
+ *
+ * @return The sum of the first and second values.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval now;
+ * gettimeofday(&now, NULL);
+ *
+ * struct timeval theEnd = parcTime_TimevalAdd(&now, timeout);
+ * }
+ * @endcode
+ */
+struct timeval parcTime_TimevalAdd(const struct timeval *addend1, const struct timeval *addend2);
+
+/**
+ * Subtract two `struct timeval` values.
+ *
+ * @param [in] minuend The number from which the subtrahend is to be subtracted.
+ * @param [in] subtrahend The subtrahend.
+ *
+ * @return The difference between the first and second values.
+ *
+ * Example:
+ * @code
+ * {
+ * struct timeval now;
+ * gettimeofday(&now, NULL);
+ *
+ * struct timeval result = parcTime_TimevalSubtract(&now, timeout);
+ * }
+ * @endcode
+ */
+struct timeval parcTime_TimevalSubtract(const struct timeval *minuend, const struct timeval *subtrahend);
+
+/**
+ * The current time as a `struct timeval`.
+ *
+ * @return The current time as a `struct timeval`.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * struct timeval now = parcTime_NowTimeval();
+ * }
+ * @endcode
+ */
+struct timeval parcTime_NowTimeval(void);
+
+/**
+ * The current time in microseconds since midnight (0 hour), January 1, 1970 as a `uint64_t`.
+ *
+ * @return The current time in microseconds since midnight (0 hour), January 1, 1970 as a `uint64_t`.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * uint64_t now = parcTime_NowMicroseconds();
+ * }
+ * @endcode
+ */
+uint64_t parcTime_NowMicroseconds(void);
+
+/**
+ * The current time in nanoseconds since midnight (0 hour), January 1, 1970 as a `uint64_t`.
+ *
+ * @return The current time in nanoseconds since midnight (0 hour), January 1, 1970 as a `uint64_t`.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * uint64_t now = parcTime_NowNanoseconds();
+ * }
+ * @endcode
+ */
+uint64_t parcTime_NowNanoseconds(void);
+#endif // libparc_parc_Time_h
diff --git a/libparc/parc/algol/parc_TreeMap.c b/libparc/parc/algol/parc_TreeMap.c
new file mode 100755
index 00000000..9c776b30
--- /dev/null
+++ b/libparc/parc/algol/parc_TreeMap.c
@@ -0,0 +1,1120 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "parc_TreeMap.h"
+#include "parc_ArrayList.h"
+#include "parc_KeyValue.h"
+
+#include <parc/algol/parc_Memory.h>
+
+#define RED 1
+#define BLACK 0
+
+#define ASSERT_INVARIANTS
+
+struct treemap_node;
+typedef struct treemap_node _RBNode;
+
+struct treemap_node {
+ _RBNode *leftChild;
+ _RBNode *rightChild;
+ _RBNode *parent;
+ PARCKeyValue *element;
+ int color;
+};
+
+struct parc_treemap {
+ _RBNode *root;
+ _RBNode *nil;
+ int size;
+ PARCTreeMap_CustomCompare *customCompare;
+};
+
+typedef void (rbRecursiveFunc)(_RBNode *node, PARCObject *data);
+
+static void
+_rbNodeFree(_RBNode *node)
+{
+ if (node->element != NULL) {
+ parcKeyValue_Release(&(node->element));
+ }
+ parcMemory_Deallocate((void **) &node);
+}
+
+static void
+_rbNodeFreeRecursive(PARCTreeMap *tree, _RBNode *node)
+{
+ if (node->leftChild != tree->nil) {
+ _rbNodeFreeRecursive(tree, node->leftChild);
+ }
+ if (node->rightChild != tree->nil) {
+ _rbNodeFreeRecursive(tree, node->rightChild);
+ }
+ // We descended on both branches, now free myself.
+ _rbNodeFree(node);
+ tree->size--;
+}
+
+// Run a function on all nodes in the tree, in order
+static void
+_rbNodeRecursiveRun(PARCTreeMap *tree, _RBNode *node, rbRecursiveFunc *func, PARCObject *data)
+{
+ if (node->leftChild != tree->nil) {
+ _rbNodeRecursiveRun(tree, node->leftChild, func, data);
+ }
+ func(node, data);
+ if (node->rightChild != tree->nil) {
+ _rbNodeRecursiveRun(tree, node->rightChild, func, data);
+ }
+}
+
+
+static _RBNode *
+_rbMinRelativeNode(const PARCTreeMap *tree, _RBNode *startNode)
+{
+ _RBNode *searchNode = startNode;
+
+ // Let's get to the bottom left
+ while (searchNode->leftChild != tree->nil) {
+ searchNode = searchNode->leftChild;
+ }
+
+ return searchNode;
+}
+
+static _RBNode *
+_rbMaxRelativeNode(const PARCTreeMap *tree, _RBNode *startNode)
+{
+ _RBNode *searchNode = startNode;
+
+ // Let's get to the bottom left
+ while (searchNode->rightChild != tree->nil) {
+ searchNode = searchNode->rightChild;
+ }
+
+ return searchNode;
+}
+
+static _RBNode *
+_rbNextNode(const PARCTreeMap *tree, _RBNode *node)
+{
+ _RBNode *searchNode = node;
+ if (searchNode->rightChild != tree->nil) {
+ searchNode = _rbMinRelativeNode(tree, searchNode->rightChild);
+ } else {
+ _RBNode *parent = searchNode->parent;
+ while (parent != tree->nil) {
+ if (parent->leftChild == searchNode) {
+ break;
+ }
+ searchNode = parent;
+ parent = searchNode->parent;
+ }
+ searchNode = parent;
+ }
+
+ return searchNode;
+}
+
+static _RBNode *
+_rbPreviousNode(const PARCTreeMap *tree, _RBNode *node)
+{
+ _RBNode *searchNode = node;
+ if (searchNode->leftChild != tree->nil) {
+ searchNode = _rbMaxRelativeNode(tree, searchNode->leftChild);
+ } else {
+ _RBNode *parent = searchNode->parent;
+ while (parent != tree->nil) {
+ if (parent->rightChild == searchNode) {
+ break;
+ }
+ searchNode = parent;
+ parent = searchNode->parent;
+ }
+ searchNode = parent;
+ }
+
+ return searchNode;
+}
+
+
+/**
+ * Create a node
+ * Set the parent and children to tree->nil.
+ * If we are creating the nil node this might leave garbage there (if not preset to NULL).
+ */
+static _RBNode *
+_rbNodeCreate(PARCTreeMap *tree, int color)
+{
+ _RBNode *node = parcMemory_AllocateAndClear(sizeof(_RBNode));
+ assertNotNull(node, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(_RBNode));
+ node->color = color;
+ node->leftChild = tree->nil;
+ node->rightChild = tree->nil;
+ node->parent = tree->nil;
+ return node;
+}
+
+static void
+_rbNodeSetColor(_RBNode *node, uint8_t color)
+{
+ node->color = color;
+}
+
+static int
+_rbNodeColor(const _RBNode *node)
+{
+ return node->color;
+}
+
+static bool
+_rbNodeIsEqual(const PARCTreeMap *tree, const _RBNode *node, const PARCObject *key)
+{
+ bool result = false;
+ if (node->element != NULL) {
+ if (tree->customCompare != NULL) {
+ result = (tree->customCompare(parcKeyValue_GetKey(node->element), key) == 0);
+ } else {
+ result = parcObject_Equals(parcKeyValue_GetKey(node->element), key);
+ }
+ }
+ return result;
+}
+
+static bool
+_rbNodeIsGreaterThan(const PARCTreeMap *tree, const _RBNode *node, const PARCObject *key)
+{
+ bool result = false;
+ if (node->element != NULL) {
+ if (tree->customCompare != NULL) {
+ result = (tree->customCompare(parcKeyValue_GetKey(node->element), key) > 0);
+ } else {
+ result = (parcObject_Compare(parcKeyValue_GetKey(node->element), key) > 0);
+ }
+ }
+ return result;
+}
+
+static _RBNode *
+_rbFindNode(const PARCTreeMap *tree, _RBNode *startNode, const PARCObject *key)
+{
+ _RBNode *result = NULL;
+ _RBNode *node = startNode;
+
+ // Let's get to the bottom of the tree to insert.
+ while (node != tree->nil) {
+ if (_rbNodeIsEqual(tree, node, key)) {
+ result = node;
+ break;
+ } else {
+ if (_rbNodeIsGreaterThan(tree, node, key)) {
+ node = node->leftChild;
+ } else {
+ node = node->rightChild;
+ }
+ }
+ }
+ return result;
+}
+
+
+static void
+_rbNodeUpdate(_RBNode *treeNode, _RBNode *newNode)
+{
+ // Free old values
+ if (treeNode->element != NULL) {
+ parcKeyValue_Release(&treeNode->element);
+ }
+
+ treeNode->element = parcKeyValue_Acquire(newNode->element);
+ _rbNodeFree(newNode);
+}
+
+static void
+_rbNodeRotateLeft(PARCTreeMap *tree, _RBNode *node)
+{
+ _RBNode *subroot = node->rightChild;
+ node->rightChild = subroot->leftChild;
+ if (node->rightChild != tree->nil) {
+ node->rightChild->parent = node;
+ }
+
+ subroot->parent = node->parent;
+ if (tree->root == node) {
+ tree->root = subroot;
+ } else {
+ if (subroot->parent->leftChild == node) {
+ // node was a left child
+ subroot->parent->leftChild = subroot;
+ } else {
+ // node was a right child
+ subroot->parent->rightChild = subroot;
+ }
+ }
+
+ subroot->leftChild = node;
+ node->parent = subroot;
+}
+
+static void
+_rbNodeRotateRight(PARCTreeMap *tree, _RBNode *node)
+{
+ _RBNode *subroot = node->leftChild;
+ node->leftChild = subroot->rightChild;
+ if (node->leftChild != tree->nil) {
+ node->leftChild->parent = node;
+ }
+
+ subroot->parent = node->parent;
+ if (tree->root == node) {
+ tree->root = subroot;
+ } else {
+ if (subroot->parent->leftChild == node) {
+ // node was a left child
+ subroot->parent->leftChild = subroot;
+ } else {
+ // node was a right child
+ subroot->parent->rightChild = subroot;
+ }
+ }
+
+ subroot->rightChild = node;
+ node->parent = subroot;
+}
+
+static void
+_rbNodeFix(PARCTreeMap *tree, _RBNode *startNode)
+{
+ _RBNode *node = startNode;
+ _RBNode *uncle;
+ while (_rbNodeColor(node->parent) == RED) {
+ if (node->parent->parent->leftChild == node->parent) {
+ uncle = node->parent->parent->rightChild;
+ if (_rbNodeColor(uncle) == RED) {
+ // My dad and uncle are red. Switch dad to black.
+ // Switch grandpa to red and start there.
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(uncle, BLACK);
+ _rbNodeSetColor(node->parent->parent, RED);
+ node = node->parent->parent;
+ } else {
+ if (node->parent->rightChild == node) {
+ node = node->parent;
+ _rbNodeRotateLeft(tree, node);
+ }
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(node->parent->parent, RED);
+ _rbNodeRotateRight(tree, node->parent->parent);
+ }
+ } else {
+ uncle = node->parent->parent->leftChild;
+ if (_rbNodeColor(uncle) == RED) {
+ // My dad and uncle are red. Switch dad to black.
+ // Switch grandpa to red and start there.
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(uncle, BLACK);
+ _rbNodeSetColor(node->parent->parent, RED);
+ node = node->parent->parent;
+ } else {
+ if (node->parent->leftChild == node) {
+ node = node->parent;
+ _rbNodeRotateRight(tree, node);
+ }
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(node->parent->parent, RED);
+ _rbNodeRotateLeft(tree, node->parent->parent);
+ }
+ }
+ }
+ _rbNodeSetColor(tree->root, BLACK);
+}
+
+static void
+_rbNodeAssertNodeInvariants(_RBNode *node, PARCObject *data)
+{
+ PARCTreeMap *tree = (PARCTreeMap *) data;
+ assertNotNull(node->parent, "Node has NULL parent");
+ assertNotNull(node->leftChild, "Left child NULL");
+ assertNotNull(node->rightChild, "Richt child NULL");
+ if (node != tree->root) {
+ assertTrue(node->parent != tree->nil, "Paren't can't be nill for node!");
+ // Don't need to compare to parent, they compared to us
+ }
+ assertNotNull(node->element, "We have a null element!!");
+ assertNotNull(parcKeyValue_GetKey(node->element), "We have a null key!!");
+ assertNotNull(parcKeyValue_GetValue(node->element), "We have a null value!!");
+ if (node->leftChild != tree->nil) {
+ if (tree->customCompare != NULL) {
+ assertTrue(tree->customCompare(parcKeyValue_GetKey(node->element), parcKeyValue_GetKey(node->leftChild->element)) > 0, "Left child not smaller?");
+ } else {
+ assertTrue(parcObject_Compare(parcKeyValue_GetKey(node->element), parcKeyValue_GetKey(node->leftChild->element)) > 0, "Left child not smaller?");
+ }
+ }
+ if (node->rightChild != tree->nil) {
+ if (tree->customCompare != NULL) {
+ assertTrue(tree->customCompare(parcKeyValue_GetKey(node->element), parcKeyValue_GetKey(node->rightChild->element)) < 0, "Right child not bigger?");
+ } else {
+ assertTrue(parcObject_Compare(parcKeyValue_GetKey(node->element), parcKeyValue_GetKey(node->rightChild->element)) < 0, "Right child not bigger?");
+ }
+ }
+}
+
+static
+void
+_rbNodeAssertTreeInvariants(const PARCTreeMap *tree)
+{
+ assertNotNull(tree, "Tree is null!");
+ assertTrue(tree->size >= 0, "Tree has negative size");
+ if (tree->size != 0) {
+ assertTrue(tree->root != tree->nil, "Tree size = %d > 0 but root is nil", tree->size);
+ assertNotNull(tree->root, "Tree size > 0 but root is NULL");
+#ifdef ASSERT_INVARIANTS
+ _rbNodeRecursiveRun((PARCTreeMap *) tree, tree->root, _rbNodeAssertNodeInvariants, (PARCObject *) tree);
+#endif
+ }
+}
+
+static void
+_rbNodeFixDelete(PARCTreeMap *tree, _RBNode *node)
+{
+ _RBNode *fixNode;
+
+ while ((node != tree->root) && (_rbNodeColor(node) == BLACK)) {
+ _rbNodeAssertTreeInvariants(tree);
+ if (node == node->parent->leftChild) {
+ fixNode = node->parent->rightChild;
+ if (_rbNodeColor(fixNode) == RED) {
+ _rbNodeSetColor(fixNode, BLACK);
+ _rbNodeSetColor(node->parent, RED);
+ _rbNodeRotateLeft(tree, node->parent);
+ fixNode = node->parent->rightChild;
+ }
+ if ((_rbNodeColor(fixNode->leftChild) == BLACK) &&
+ (_rbNodeColor(fixNode->rightChild) == BLACK)) {
+ _rbNodeSetColor(fixNode, RED);
+ node = node->parent;
+ } else {
+ if (_rbNodeColor(fixNode->rightChild) == BLACK) {
+ _rbNodeSetColor(fixNode->leftChild, BLACK);
+ _rbNodeSetColor(fixNode, RED);
+ _rbNodeRotateRight(tree, fixNode);
+ fixNode = node->parent->rightChild;
+ }
+ _rbNodeSetColor(fixNode, _rbNodeColor(node->parent));
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(fixNode->rightChild, BLACK);
+ _rbNodeRotateLeft(tree, node->parent);
+ node = tree->root;
+ }
+ } else {
+ fixNode = node->parent->leftChild;
+ if (_rbNodeColor(fixNode) == RED) {
+ _rbNodeSetColor(fixNode, BLACK);
+ _rbNodeSetColor(node->parent, RED);
+ _rbNodeRotateRight(tree, node->parent);
+ fixNode = node->parent->leftChild;
+ }
+ if ((_rbNodeColor(fixNode->leftChild) == BLACK) &&
+ (_rbNodeColor(fixNode->rightChild) == BLACK)) {
+ _rbNodeSetColor(fixNode, RED);
+ node = node->parent;
+ } else {
+ if (_rbNodeColor(fixNode->leftChild) == BLACK) {
+ _rbNodeSetColor(fixNode->rightChild, BLACK);
+ _rbNodeSetColor(fixNode, RED);
+ _rbNodeRotateLeft(tree, fixNode);
+ fixNode = node->parent->leftChild;
+ }
+ _rbNodeSetColor(fixNode, _rbNodeColor(node->parent));
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(fixNode->leftChild, BLACK);
+ _rbNodeRotateRight(tree, node->parent);
+ node = tree->root;
+ }
+ }
+ }
+
+ _rbNodeSetColor(node, BLACK);
+}
+
+// Remove the node from the tree.
+// The node must be part of a tree (with parents and children)
+static void
+_rbNodeRemove(PARCTreeMap *tree, _RBNode *node)
+{
+ _rbNodeAssertTreeInvariants(tree);
+ _RBNode *fixupNode;
+ int deleteNodeColor = _rbNodeColor(node);
+ if (node->leftChild == tree->nil) {
+ if (node->rightChild == tree->nil) {
+ // ---- We have no children ----
+ if (tree->root == node) {
+ tree->root = tree->nil;
+ } else {
+ if (node->parent->leftChild == node) {
+ node->parent->leftChild = tree->nil;
+ } else {
+ node->parent->rightChild = tree->nil;
+ }
+ }
+ fixupNode = tree->nil;
+ fixupNode->parent = node->parent;
+ } else {
+ // ---- We only have right child, move up ----
+ if (tree->root == node) {
+ tree->root = node->rightChild;
+ } else {
+ if (node->parent->leftChild == node) {
+ node->parent->leftChild = node->rightChild;
+ } else {
+ node->parent->rightChild = node->rightChild;
+ }
+ }
+ fixupNode = node->rightChild;
+ node->rightChild->parent = node->parent;
+ }
+ } else {
+ if (node->rightChild == tree->nil) {
+ // ---- We only have left child, move up ----
+ if (tree->root == node) {
+ tree->root = node->leftChild;
+ } else {
+ if (node->parent->leftChild == node) {
+ node->parent->leftChild = node->leftChild;
+ } else {
+ node->parent->rightChild = node->leftChild;
+ }
+ }
+ node->leftChild->parent = node->parent;
+ fixupNode = node->leftChild;
+ } else {
+ // ---- We have 2 children, move our successor to our location ----
+ _RBNode *successor = node->rightChild;
+ while (successor->leftChild != tree->nil) {
+ successor = successor->leftChild;
+ }
+ deleteNodeColor = _rbNodeColor(successor);
+
+ // Remove successor, it has no left child
+ if (successor == successor->parent->leftChild) {
+ successor->parent->leftChild = successor->rightChild;
+ } else {
+ successor->parent->rightChild = successor->rightChild;
+ }
+ successor->rightChild->parent = successor->parent;
+
+ fixupNode = successor->rightChild;
+
+ if (node->parent == tree->nil) {
+ tree->root = successor;
+ } else if (node->parent->leftChild == node) {
+ node->parent->leftChild = successor;
+ } else {
+ node->parent->rightChild = successor;
+ }
+ successor->parent = node->parent;
+ successor->leftChild = node->leftChild;
+ node->leftChild->parent = successor;
+ successor->rightChild = node->rightChild;
+ node->rightChild->parent = successor;
+
+ _rbNodeSetColor(successor, _rbNodeColor(node));
+
+ if (successor->parent == tree->nil) {
+ tree->root = successor;
+ }
+ }
+ }
+ tree->size--;
+
+ // Fix the red-blackness
+ _rbNodeAssertTreeInvariants(tree);
+ if (deleteNodeColor == BLACK) {
+ _rbNodeFixDelete(tree, fixupNode);
+ }
+ _rbNodeAssertTreeInvariants(tree);
+}
+
+static void
+_parcTreeMap_Destroy(PARCTreeMap **treePointer)
+{
+ assertNotNull(treePointer, "pointer to pointer to tree can't be null");
+ assertNotNull(*treePointer, "pointer to tree can't be null");
+ _rbNodeAssertTreeInvariants(*treePointer);
+
+ if ((*treePointer)->size > 0) {
+ // If we have any elements in the tree, free them
+ _rbNodeFreeRecursive(*treePointer, (*treePointer)->root);
+ }
+
+ // Free the nil element
+ parcMemory_Deallocate((void **) &((*treePointer)->nil));
+}
+
+
+parcObject_ExtendPARCObject(PARCTreeMap, _parcTreeMap_Destroy, parcTreeMap_Copy, NULL, parcTreeMap_Equals, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(parcTreeMap, PARCTreeMap);
+
+parcObject_ImplementRelease(parcTreeMap, PARCTreeMap);
+
+PARCTreeMap *
+parcTreeMap_CreateCustom(PARCTreeMap_CustomCompare *customCompare)
+{
+ PARCTreeMap *tree = parcObject_CreateInstance(PARCTreeMap);
+ assertNotNull(tree, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCTreeMap));
+ tree->nil = _rbNodeCreate(tree, BLACK);
+ tree->nil->leftChild = tree->nil;
+ tree->nil->rightChild = tree->nil;
+ tree->nil->parent = tree->nil;
+ tree->root = tree->nil;
+ tree->customCompare = customCompare;
+ tree->size = 0;
+ return tree;
+}
+
+PARCTreeMap *
+parcTreeMap_Create(void)
+{
+ return parcTreeMap_CreateCustom(NULL);
+}
+
+void
+parcTreeMap_Put(PARCTreeMap *tree, const PARCObject *key, const PARCObject *value)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ assertNotNull(key, "Key can't be NULL");
+ assertNotNull(value, "Value can't be NULL");
+
+ _RBNode *newNode = _rbNodeCreate(tree, RED);
+ _RBNode *parent = tree->nil;
+ _RBNode *node;
+
+ // Set the value for the created node
+ PARCKeyValue *element = parcKeyValue_Create(key, value);
+ newNode->element = element;
+
+ // Start at the top
+ node = tree->root;
+
+ // Let's get to the bottom of the tree to insert.
+ while (node != tree->nil) {
+ parent = node;
+ if (_rbNodeIsEqual(tree, node, key)) {
+ // We're trying to insert the same value
+ _rbNodeUpdate(node, newNode);
+ return;
+ } else {
+ if (_rbNodeIsGreaterThan(tree, node, key)) {
+ // The key is smaller
+ node = node->leftChild;
+ } else {
+ node = node->rightChild;
+ }
+ }
+ }
+
+ // We're at the bottom.
+ // node is nil (a leaf)
+ newNode->parent = parent;
+ if (parent == tree->nil) {
+ // nil is our parent, we are the root
+ tree->root = newNode;
+ } else {
+ if (_rbNodeIsGreaterThan(tree, parent, key)) {
+ parent->leftChild = newNode;
+ } else {
+ parent->rightChild = newNode;
+ }
+ }
+
+ // We have inserted one node.
+ tree->size++;
+
+ // We have a correct tree. But we need to regain the red-black property.
+ _rbNodeFix(tree, newNode);
+
+ _rbNodeAssertTreeInvariants(tree);
+}
+
+PARCObject *
+parcTreeMap_Get(PARCTreeMap *tree, const PARCObject *key)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+
+ PARCObject *result = NULL;
+
+ _RBNode *node = _rbFindNode(tree, tree->root, key);
+
+ if (node != NULL) {
+ result = parcKeyValue_GetValue(node->element);
+ }
+
+ return result;
+}
+
+// Return value, remove from tree
+PARCObject *
+parcTreeMap_Remove(PARCTreeMap *tree, const PARCObject *key)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ assertNotNull(key, "Key can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+
+ PARCObject *result = NULL;
+
+ _RBNode *node = _rbFindNode(tree, tree->root, key);
+
+ if (node != NULL) {
+ _rbNodeRemove(tree, node);
+ result = parcObject_Acquire(parcKeyValue_GetValue(node->element));
+ _rbNodeFree(node);
+ }
+
+ // We didn't find the node
+
+ _rbNodeAssertTreeInvariants(tree);
+
+ return result;
+}
+
+// remove from tree and destroy
+void
+parcTreeMap_RemoveAndRelease(PARCTreeMap *tree, const PARCObject *key)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ assertNotNull(key, "Key can't be NULL");
+
+ _RBNode *node = _rbFindNode(tree, tree->root, key);
+
+ if (node != NULL) {
+ _rbNodeRemove(tree, node);
+ _rbNodeFree(node);
+ }
+
+ _rbNodeAssertTreeInvariants(tree);
+}
+
+PARCKeyValue *
+parcTreeMap_GetLastEntry(const PARCTreeMap *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+ _RBNode *node = tree->root;
+
+ if (tree->size == 0) {
+ // We don't have any entries
+ return NULL;
+ }
+
+ // Let's get to the bottom right of the tree to find the largest
+ while (node->rightChild != tree->nil) {
+ node = node->rightChild;
+ }
+
+ return node->element;
+}
+
+PARCObject *
+parcTreeMap_GetLastKey(const PARCTreeMap *tree)
+{
+ PARCObject *result = NULL;
+
+ PARCKeyValue *entry = parcTreeMap_GetLastEntry(tree);
+ if (entry != NULL) {
+ result = parcKeyValue_GetKey(entry);
+ }
+
+ return result;
+}
+
+PARCKeyValue *
+parcTreeMap_GetFirstEntry(const PARCTreeMap *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+
+ if (tree->size == 0) {
+ // We don't have any entries
+ return NULL;
+ }
+
+ _RBNode *node = _rbMinRelativeNode(tree, tree->root);
+
+ return node->element;
+}
+
+PARCObject *
+parcTreeMap_GetFirstKey(const PARCTreeMap *tree)
+{
+ PARCObject *result = NULL;
+
+ PARCKeyValue *entry = parcTreeMap_GetFirstEntry(tree);
+ if (entry != NULL) {
+ result = parcKeyValue_GetKey(entry);
+ }
+
+ return result;
+}
+
+PARCKeyValue *
+parcTreeMap_GetHigherEntry(const PARCTreeMap *tree, const PARCObject *key)
+{
+ PARCKeyValue *result = NULL;
+
+ _RBNode *node = _rbFindNode(tree, tree->root, key);
+ if (node != NULL) {
+ node = _rbNextNode(tree, node);
+ if (node != NULL) {
+ result = node->element;
+ }
+ }
+
+ return result;
+}
+
+PARCObject *
+parcTreeMap_GetHigherKey(const PARCTreeMap *tree, const PARCObject *key)
+{
+ PARCObject *result = NULL;
+
+ PARCKeyValue *kv = parcTreeMap_GetHigherEntry(tree, key);
+ if (kv != NULL) {
+ result = parcKeyValue_GetKey(kv);
+ }
+
+ return result;
+}
+
+PARCKeyValue *
+parcTreeMap_GetLowerEntry(const PARCTreeMap *tree, const PARCObject *key)
+{
+ PARCKeyValue *result = NULL;
+
+ _RBNode *node = _rbFindNode(tree, tree->root, key);
+ if (node != NULL) {
+ node = _rbPreviousNode(tree, node);
+ if (node != NULL) {
+ result = node->element;
+ }
+ }
+
+ return result;
+}
+
+PARCObject *
+parcTreeMap_GetLowerKey(const PARCTreeMap *tree, const PARCObject *key)
+{
+ PARCObject *result = NULL;
+
+ PARCKeyValue *kv = parcTreeMap_GetLowerEntry(tree, key);
+ if (kv != NULL) {
+ result = parcKeyValue_GetKey(kv);
+ }
+
+ return result;
+}
+
+
+size_t
+parcTreeMap_Size(const PARCTreeMap *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+
+ return tree->size;
+}
+
+static void
+_rbAddKeyToList(_RBNode *node, PARCList *list)
+{
+ parcList_Add(list, parcObject_Acquire(parcKeyValue_GetKey(node->element)));
+}
+
+static void
+_rbAddalueToList(_RBNode *node, PARCList *list)
+{
+ parcList_Add(list, parcObject_Acquire(parcKeyValue_GetValue(node->element)));
+}
+
+static void
+_rbAddElementToList(_RBNode *node, PARCList *list)
+{
+ parcList_Add(list, parcObject_Acquire(node->element));
+}
+
+PARCList *
+parcTreeMap_AcquireKeys(const PARCTreeMap *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+
+ PARCList *keys = parcList(parcArrayList_Create_Capacity((bool (*)(void *x, void *y))parcObject_Equals,
+ (void (*)(void **))parcObject_Release, tree->size),
+ PARCArrayListAsPARCList);
+
+ if (tree->size > 0) {
+ _rbNodeRecursiveRun((PARCTreeMap *) tree, tree->root, (rbRecursiveFunc *) _rbAddKeyToList, keys);
+ }
+ return keys;
+}
+
+PARCList *
+parcTreeMap_AcquireValues(const PARCTreeMap *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+
+ PARCList *values = parcList(parcArrayList_Create_Capacity((bool (*)(void *x, void *y))parcObject_Equals,
+ (void (*)(void **))parcObject_Release, tree->size),
+ PARCArrayListAsPARCList);
+
+ if (tree->size > 0) {
+ _rbNodeRecursiveRun((PARCTreeMap *) tree, tree->root, (rbRecursiveFunc *) _rbAddalueToList, values);
+ }
+ return values;
+}
+
+static PARCList *
+_parcTreeMap_Elements(const PARCTreeMap *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+
+ PARCList *elements = parcList(parcArrayList_Create_Capacity((bool (*)(void *x, void *y))parcObject_Equals,
+ (void (*)(void **))parcObject_Release, tree->size),
+ PARCArrayListAsPARCList);
+
+ if (tree->size > 0) {
+ _rbNodeRecursiveRun((PARCTreeMap *) tree, tree->root, (rbRecursiveFunc *) _rbAddElementToList, elements);
+ }
+ return elements;
+}
+
+bool
+parcTreeMap_Equals(const PARCTreeMap *tree1, const PARCTreeMap *tree2)
+{
+ _rbNodeAssertTreeInvariants(tree1);
+ _rbNodeAssertTreeInvariants(tree2);
+ assertNotNull(tree1, "Tree can't be NULL");
+ assertNotNull(tree2, "Tree can't be NULL");
+
+ bool result = false;
+
+ PARCList *keys1 = parcTreeMap_AcquireKeys(tree1);
+ PARCList *keys2 = parcTreeMap_AcquireKeys(tree2);
+ size_t length1 = parcList_Size(keys1);
+ size_t length2 = parcList_Size(keys2);
+
+ if (length1 == length2) {
+ result = true;
+ for (size_t i = 0; i < length1; i++) {
+ if (!parcObject_Equals(parcList_GetAtIndex(keys1, i), parcList_GetAtIndex(keys2, i))) {
+ result = false;
+ break;
+ }
+ }
+ if (result) {
+ PARCList *values1 = parcTreeMap_AcquireValues(tree1);
+ PARCList *values2 = parcTreeMap_AcquireValues(tree2);
+ size_t s1 = parcList_Size(values1);
+ size_t s2 = parcList_Size(values2);
+ if (s1 == s2) {
+ for (size_t i = 0; i < s1; i++) {
+ PARCObject *value1 = parcList_GetAtIndex(values1, i);
+ PARCObject *value2 = parcList_GetAtIndex(values2, i);
+ if (!parcObject_Equals(value1, value2)) {
+ result = false;
+ break;
+ }
+ }
+ }
+ parcList_Release(&values1);
+ parcList_Release(&values2);
+ }
+ }
+
+ parcList_Release(&keys1);
+ parcList_Release(&keys2);
+ return result;
+}
+
+
+/*
+ * This is a simple implementation of Copy that goes through the list of keys and values.
+ */
+PARCTreeMap *
+parcTreeMap_Copy(const PARCTreeMap *sourceTree)
+{
+ _rbNodeAssertTreeInvariants(sourceTree);
+ assertNotNull(sourceTree, "Tree can't be NULL");
+
+ PARCObject *keySource;
+ PARCObject *keyCopy;
+ PARCObject *valueSource;
+ PARCObject *valueCopy;
+
+ PARCTreeMap *treeCopy = parcTreeMap_CreateCustom(sourceTree->customCompare);
+
+ PARCList *keys = parcTreeMap_AcquireKeys(sourceTree);
+ PARCList *values = parcTreeMap_AcquireValues(sourceTree);
+
+ size_t total_keys = parcList_Size(keys);
+
+ for (size_t i = 0; i < total_keys; i++) {
+ keySource = parcList_GetAtIndex(keys, i);
+ valueSource = parcList_GetAtIndex(values, i);
+
+ keyCopy = parcObject_Copy(keySource);
+ valueCopy = parcObject_Copy(valueSource);
+
+ parcTreeMap_Put(treeCopy, keyCopy, valueCopy);
+ parcObject_Release(&keyCopy);
+ parcObject_Release(&valueCopy);
+ }
+
+ parcList_Release(&keys);
+ parcList_Release(&values);
+
+ return treeCopy;
+}
+
+////// Iterator Support //////
+
+typedef struct {
+ PARCTreeMap *map;
+ PARCList *list;
+ size_t currentIndex;
+ PARCKeyValue *currentElement;
+} _PARCTreeMapIterator;
+
+static _PARCTreeMapIterator *
+_parcTreeMapIterator_Init(PARCTreeMap *map)
+{
+ _PARCTreeMapIterator *state = parcMemory_AllocateAndClear(sizeof(_PARCTreeMapIterator));
+
+ if (state != NULL) {
+ state->map = map;
+ state->list = _parcTreeMap_Elements(map);
+ state->currentIndex = 0;
+ state->currentElement = parcList_GetAtIndex(state->list, 0);
+ trapOutOfMemoryIf(state->list == NULL, "Cannot create parcList");
+ }
+
+ return state;
+}
+
+static bool
+_parcTreeMapIterator_Fini(PARCTreeMap *map __attribute__((unused)), _PARCTreeMapIterator *state __attribute__((unused)))
+{
+ parcList_Release(&state->list);
+ parcMemory_Deallocate(&state);
+ return true;
+}
+
+static _PARCTreeMapIterator *
+_parcTreeMapIterator_Next(PARCTreeMap *map __attribute__((unused)), _PARCTreeMapIterator *state)
+{
+ state->currentElement = parcList_GetAtIndex(state->list, state->currentIndex);
+ ++state->currentIndex;
+ return state;
+}
+
+static void
+_parcTreeMapIterator_Remove(PARCTreeMap *map, _PARCTreeMapIterator **statePtr)
+{
+ _PARCTreeMapIterator *state = *statePtr;
+
+ parcTreeMap_RemoveAndRelease(map, parcKeyValue_GetKey(state->currentElement));
+}
+
+static bool
+_parcTreeMapIterator_HasNext(PARCTreeMap *map __attribute__((unused)), _PARCTreeMapIterator *state)
+{
+ return (parcList_Size(state->list) > state->currentIndex);
+}
+
+static PARCObject *
+_parcTreeMapIterator_Element(PARCTreeMap *map __attribute__((unused)), const _PARCTreeMapIterator *state)
+{
+ return state->currentElement;
+}
+
+static PARCObject *
+_parcTreeMapIterator_ElementValue(PARCTreeMap *map __attribute__((unused)), const _PARCTreeMapIterator *state)
+{
+ return parcKeyValue_GetValue(state->currentElement);
+}
+
+static PARCObject *
+_parcTreeMapIterator_ElementKey(PARCTreeMap *map __attribute__((unused)), const _PARCTreeMapIterator *state)
+{
+ return parcKeyValue_GetKey(state->currentElement);
+}
+
+PARCIterator *
+parcTreeMap_CreateValueIterator(PARCTreeMap *treeMap)
+{
+ PARCIterator *iterator = parcIterator_Create(treeMap,
+ (void *(*)(PARCObject *))_parcTreeMapIterator_Init,
+ (bool (*)(PARCObject *, void *))_parcTreeMapIterator_HasNext,
+ (void *(*)(PARCObject *, void *))_parcTreeMapIterator_Next,
+ (void (*)(PARCObject *, void **))_parcTreeMapIterator_Remove,
+ (void *(*)(PARCObject *, void *))_parcTreeMapIterator_ElementValue,
+ (void (*)(PARCObject *, void *))_parcTreeMapIterator_Fini,
+ NULL);
+
+ return iterator;
+}
+
+
+PARCIterator *
+parcTreeMap_CreateKeyIterator(PARCTreeMap *treeMap)
+{
+ PARCIterator *iterator = parcIterator_Create(treeMap,
+ (void *(*)(PARCObject *))_parcTreeMapIterator_Init,
+ (bool (*)(PARCObject *, void *))_parcTreeMapIterator_HasNext,
+ (void *(*)(PARCObject *, void *))_parcTreeMapIterator_Next,
+ (void (*)(PARCObject *, void **))_parcTreeMapIterator_Remove,
+ (void *(*)(PARCObject *, void *))_parcTreeMapIterator_ElementKey,
+ (void (*)(PARCObject *, void *))_parcTreeMapIterator_Fini,
+ NULL);
+
+ return iterator;
+}
+
+PARCIterator *
+parcTreeMap_CreateKeyValueIterator(PARCTreeMap *treeMap)
+{
+ PARCIterator *iterator = parcIterator_Create(treeMap,
+ (void *(*)(PARCObject *))_parcTreeMapIterator_Init,
+ (bool (*)(PARCObject *, void *))_parcTreeMapIterator_HasNext,
+ (void *(*)(PARCObject *, void *))_parcTreeMapIterator_Next,
+ (void (*)(PARCObject *, void **))_parcTreeMapIterator_Remove,
+ (void *(*)(PARCObject *, void *))_parcTreeMapIterator_Element,
+ (void (*)(PARCObject *, void *))_parcTreeMapIterator_Fini,
+ NULL);
+
+ return iterator;
+}
diff --git a/libparc/parc/algol/parc_TreeMap.h b/libparc/parc/algol/parc_TreeMap.h
new file mode 100755
index 00000000..5f0ed8d8
--- /dev/null
+++ b/libparc/parc/algol/parc_TreeMap.h
@@ -0,0 +1,714 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_TreeMap.h
+ * @ingroup datastructures
+ * @brief A Red-Black tree containing PARCObject keys and values.
+ *
+ * The map is sorted according to the natural ordering of its keys,
+ * or by a comparator function provided at creation time, depending on which constructor is used.
+ *
+ */
+#ifndef libparc_parc_TreeMap_h
+#define libparc_parc_TreeMap_h
+
+#include <stdlib.h>
+
+#include "parc_Object.h"
+#include "parc_KeyValue.h"
+#include "parc_List.h"
+#include "parc_Iterator.h"
+
+struct parc_treemap;
+typedef struct parc_treemap PARCTreeMap;
+
+/**
+ * Definition of a custom funcion to compare two keys. A function of
+ * this signature can be provided to CreateCustom(...) constructor to
+ * override the default parcObject_Compare(...) for comparing key
+ * objects. This will be used during all internal comparisons.
+ *
+ * @param [in] key1 The first key to compare
+ * @param [in] key2 The second key to compare
+ *
+ * @return A signum comparison. negative if key1 is smaller than key2,
+ * 0 if equal, positive if key1 is bigger.
+ *
+ * Example:
+ * @code
+ * {
+ * int _compareKeys(const PARCObject *key1, const PARCObject *key2) {...}
+ *
+ * PARCTreeMap * tree1 = parcTreeMap_CreateCustom(_compareKeys);
+ *
+ * ...
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+typedef int (PARCTreeMap_CustomCompare)(const PARCObject *key1, const PARCObject *key2);
+
+/**
+ * Create a standard `PARCTreeMap` that uses parcObject_Compare for
+ * comparisons.
+ *
+ * @return NULL Error allocating memory
+ * @return Non-NULL An initialized TreeMap
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCTreeMap *parcTreeMap_Create(void);
+
+/**
+ * Create a `PARCTreeMap` that uses the provided custom compare
+ * function for key comparisons.
+ *
+ * @param [in] customCompare A cusom function to compare keys (required)
+ * @return NULL Error allocating memory
+ * @return Non-NULL An initialized RedBlack tree
+ *
+ * Example:
+ * @code
+ * {
+ * int _compareKeys(const PARCObject *key1, const PARCObject *key2) {...}
+ *
+ * PARCTreeMap * tree1 = parcTreeMap_CreateCustom(_compareKeys);
+ *
+ * ...
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCTreeMap *parcTreeMap_CreateCustom(PARCTreeMap_CustomCompare *customCompare);
+
+/**
+ * Acquire a reference to a `PARCTreeMap`.
+ *
+ * @param tree The tree reference to acquire.
+ *
+ * @return the acquired reference.
+ *
+ */
+PARCTreeMap *parcTreeMap_Acquire(const PARCTreeMap *tree);
+
+/**
+ * Release a reference to a `PARCTreeMap` object. If it is the last
+ * reference, the object itself is freed and the specified free
+ * function is invoked on the stored keys and values.
+ *
+ * @param [in,out] treePointer A pointer to a pointer to the `PARCTreeMap` to be released.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+void parcTreeMap_Release(PARCTreeMap **treePointer);
+
+/**
+ * Insert a value into the `PARCTreeMap`. If the key exists in the
+ * tree then the new value will replace the old value. The old key and
+ * value will be released by the map and the map will acquire a
+ * reference to the new key and value. The key must not be NULL.
+ *
+ * @param [in, out] tree A pointer to an initialized `PARCTreeMap`.
+ * @param [in] key A pointer to a key - This may not be NULL.
+ * @param [in] value A pointer to a value.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * PARCObject *someKey = ...;
+ * PARCObject *someValue = ...;
+ *
+ * parcTreeMap_Put(tree1, someKey, someValue);
+ *
+ * parcObject_Release(&someKey);
+ * parcObject_Release(&someValue);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+void parcTreeMap_Put(PARCTreeMap *tree, const PARCObject *key, const PARCObject *value);
+
+/**
+ * Checks to see if a PARCTreeMap already contains a key.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @param [in] key A pointer to a key - This may not be NULL.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = ...;
+ *
+ * if (parcTreeMap_ContainsKey(tree1, someKey) {
+ * ...
+ * }
+ *
+ * parcObject_Release(&someKey);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+bool parcTreeMap_ContainsKey(PARCTreeMap *tree, PARCObject *key);
+
+/**
+ * Get a value from a `PARCTreeMap`. If the key is not found in the
+ * tree NULL is returned. The returned value will still be owned by
+ * the tree.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @param [in] key A pointer to a key (The tree will not own this).
+ * @return A pointer to a value. You do not own this value (it's still in the tree).
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = ...;
+ *
+ * PARCObject *someValue = parcTreeMap_Get(tree1, someKey);
+ * if (someValue != NULL) {
+ * ...
+ * }
+ *
+ * parcObject_Release(&someKey);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCObject *parcTreeMap_Get(PARCTreeMap *tree, const PARCObject *key);
+
+/**
+ * Get the first (smallest) key from a `PARCTreeMap`. The returned key
+ * will still be owned by the tree. If the tree is empty the function
+ * will return NULL.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @return A pointer to the smallest key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = parcTreeMap_GetFirstKey(tree1);
+ * if (someKey != NULL) {
+ * ...
+ * }
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCObject *parcTreeMap_GetFirstKey(const PARCTreeMap *tree);
+
+/**
+ * Get the first entry (one with the smallest key) from a
+ * `PARCTreeMap`. The returned PARCKeyValue will still be owned by the
+ * tree. If the tree is empty the function will return NULL.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @return A pointer to the entry (a PARCKeyValue) with the smallest key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCKeyValue *someEntry = parcTreeMap_GetFirstEntry(tree1);
+ * if (someEntry != NULL) {
+ * ...
+ * }
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCKeyValue *parcTreeMap_GetFirstEntry(const PARCTreeMap *tree);
+
+/**
+ * Get the last (largest) key from a `PARCTreeMap`. The returned key
+ * will still be owned by the tree. If the tree is empty the function
+ * will return NULL
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @return A pointer to the largest key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = parcTreeMap_GetLastKey(tree1);
+ * if (someKey != NULL) {
+ * ...
+ * }
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCObject *parcTreeMap_GetLastKey(const PARCTreeMap *tree);
+
+/**
+ * Get the last entry (entry with the largest key) from a
+ * `PARCTreeMap`. The returned entry will still be owned by the tree.
+ * If the tree is empty the function will return NULL
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @return A pointer to the entry (a PARCKeyValue) with the largest key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCKeyValue *lastEntry = parcTreeMap_GetLastEntry(tree1);
+ * if (lastEntry != NULL) {
+ * ...
+ * }
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCKeyValue *parcTreeMap_GetLastEntry(const PARCTreeMap *tree);
+
+/**
+ * Get the next largest key from a `PARCTreeMap`. The returned key
+ * will still be owned by the tree. If the tree is empty or the
+ * supplied key is the largest, the function will return NULL
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @return A pointer to the next key. You do not own this value (it's still in the tree).
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = ...;
+ *
+ * PARCObject *nextKey = parcTreeMap_GetHigherKey(tree1, someKey);
+ * if (nextKey != NULL) {
+ * ...
+ * }
+ *
+ * parcObject_Release(&someKey);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCObject *parcTreeMap_GetHigherKey(const PARCTreeMap *tree, const PARCObject *key);
+
+/**
+ * Get the entry with the next largest key from a `PARCTreeMap`. The
+ * returned entry will still be owned by the tree. If the tree is
+ * empty or the supplied key is the largest, the function will return
+ * NULL.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @return A pointer to the next entry (a PARCKeyValue). The caller
+ * does not own this return.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = ...;
+ *
+ * PARCKeyValue *nextEntry = parcTreeMap_GetHigherEntry(tree1, someKey);
+ * if (nextEntry != NULL) {
+ * ...
+ * }
+ *
+ * parcObject_Release(&someKey);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCKeyValue *parcTreeMap_GetHigherEntry(const PARCTreeMap *tree, const PARCObject *key);
+
+/**
+ * Get the previous key from a `PARCTreeMap`. The returned key will
+ * still be owned by the tree. If the tree is empty or the supplied
+ * key is the smallest in the tree, the function will return NULL.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @param [in] key A pointer to an key
+ * @return A pointer to the previous key. The caller
+ * does not own this return.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = ...;
+ *
+ * PARCObject *previousKey = parcTreeMap_GetLowerKey(tree1, someKey);
+ * if (previousKey != NULL) {
+ * ...
+ * }
+ *
+ * parcObject_Release(&someKey);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCObject *parcTreeMap_GetLowerKey(const PARCTreeMap *tree, const PARCObject *key);
+
+/**
+ * Get the entry with the next smallest key from a `PARCTreeMap`. The returned entry (a PARCKeyValue) will
+ * still be owned by the tree. If the tree is empty or the supplied
+ * key is the smallest in the tree, the function will return NULL.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @param [in] key A pointer to an key
+ * @return A pointer to the previous entry (a PARCKeyValue). The caller
+ * does not own this return.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = ...;
+ *
+ * PARCKeyValue *previousEntry = parcTreeMap_GetLowerKey(tree1, someKey);
+ * if (previousEntry != NULL) {
+ * ...
+ * }
+ *
+ * parcObject_Release(&someKey);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCKeyValue *parcTreeMap_GetLowerEntry(const PARCTreeMap *tree, const PARCObject *key);
+
+/**
+ * Remove an entry from a `PARCTreeMap`. The entry will be removed
+ * from the tree and the tree's reference to the key will be
+ * released. The value will be returned and responsibility for
+ * releasing the reference to the value will transfer to the caller.
+ * The provided key will not be modified. If the key is not found in
+ * the tree, NULL is returned.
+ *
+ * @param [in,out] tree A pointer to an initialized `PARCTreeMap`.
+ * @param [in] key A pointer to a key (The tree will not own this).
+ * @return A pointer to a value or NULL. You will now own this value.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = ...;
+ *
+ * PARCObject *someValue = parcTreeMap_Remove(tree1, someKey);
+ * if (someValue != NULL) {
+ * ...
+ * parcObject_Release(&someValue);
+ * }
+ *
+ * parcObject_Release(&someKey);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCObject *parcTreeMap_Remove(PARCTreeMap *tree, const PARCObject *key);
+
+/**
+ * Remove and destroy an entry from a `PARCTreeMap`. The entry along with
+ * it's key & value will be removed and released.
+ *
+ * @param [in,out] tree A pointer to an initialized `PARCTreeMap`.
+ * @param [in] key A pointer to a key (The tree will not own this).
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCObject *someKey = ...;
+ *
+ * parcTreeMap_RemoveAndRelease(tree1, someKey);
+ *
+ * parcObject_Release(&someKey);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+void parcTreeMap_RemoveAndRelease(PARCTreeMap *tree, const PARCObject *key);
+
+/**
+ * Get the size (nuber of elements) of a `PARCTreeMap`.
+ *
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeMap`.
+ * @return size of the tree (number of elements).
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * if (parcTreeMap_Size(tree1) > 0) {
+ * ...
+ * }
+ *
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+size_t parcTreeMap_Size(const PARCTreeMap *tree);
+
+/**
+ * Get a PARCList of the keys from a `PARCTreeMap`. All keys will be
+ * valid keys in the `PARCTreeMap`. The caller will own the list of
+ * keys and should release it when done. The caller will not own the
+ * keys themselves. Note that if the tree is modified or destroyed
+ * the key pointers might no longer point to valid keys. The list of
+ * keys will be sorted as per the provided or key's default compare function.
+ *
+ * @param [in] tree A pointer to a `PARCTreeMap`.
+ * @return A list of (pointers to) keys.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCList *keys = parcTreeMap_AcquireKeys(tree1);
+ * for (size_t i=0; i < parcList_Size(keys); ++i) {
+ * ...
+ * }
+ *
+ * parcList_Release(&keys);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCList *parcTreeMap_AcquireKeys(const PARCTreeMap *tree);
+
+/**
+ * Get an PARCList of the values in this `PARCTreeMap`. All of these
+ * values will be valid in the `PARCTreeMap`. The caller will own the
+ * list of values and should release it when done. The list of values
+ * will be sorted as per the provided or key's default compare
+ * function.
+ *
+ * @param [in] tree A pointer to a `PARCTreeMap`.
+ * @return A list of (pointers to) values.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * PARCList *values = parcTreeMap_AcquireValues(tree1);
+ * for (size_t i=0; i < parcList_Size(values); ++i) {
+ * ...
+ * }
+ *
+ * parcList_Release(&keys);
+ * parcTreeMap_Release(&tree1);
+ * }
+ * @endcode
+ */
+PARCList *parcTreeMap_AcquireValues(const PARCTreeMap *tree);
+
+/**
+ * Calculate if two `PARCTreeMap`s are equal.
+ *
+ * Two trees are equal if they have the same keys associated with the
+ * same values. The keys & values will be compared using the
+ * parcObject_Equals(...);
+ *
+ * @param [in] tree1 A pointer to a `PARCTreeMap`.
+ * @param [in] tree2 A pointer to another `PARCTreeMap`.
+ * @return true if the trees are equal, zero otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * tree1 = parcTreeMap_Create(.....);
+ * PARCTreeMap * tree2 = parcTreeMap_Create(.....);
+ *
+ * ...
+ *
+ * if (parcTreeMap_Equals(tree1, tree2)) {
+ * ...
+ * }
+ *
+ * parcTreeMap_Release(&tree1);
+ * parcTreeMap_Release(&tree2);
+ * }
+ * @endcode
+ */
+bool parcTreeMap_Equals(const PARCTreeMap *tree1, const PARCTreeMap *tree2);
+
+/**
+ * Copy a TreeMap.
+ *
+ * This will create a completely new tree. It will copy every key and
+ * every value using parcObject_Copy(...).
+ *
+ * @param [in] sourceTree A pointer to a `PARCTreeMap` to be copied
+ * @return NULL Error copying the tree.
+ * @return Non-NULL A copy of the `PARCTreeMap`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeMap * source_tree = parcTreeMap_Create(.....);
+ *
+ * ... operations on tree ...
+ *
+ * PARCTreeMap * tree_copy = parcTreeMap_Copy(source_tree);
+ *
+ * ... operations on tree ...
+ *
+ * parcTreeMap_Release(&source_tree);
+ * parcTreeMap_Release(&tree_copy);
+ * }
+ * @endcode
+ */
+PARCTreeMap *parcTreeMap_Copy(const PARCTreeMap *sourceTree);
+
+
+/**
+ * Create a new instance of PARCIterator that iterates through the keys of the specified `PARCTreeMap`.
+ * The returned iterator must be released via {@link parcIterator_Release}.
+ *
+ * @param [in] hashMap A pointer to a valid `PARCTreeMap`.
+ *
+ * @see parcIterator_Release
+ * Example:
+ * @code
+ * {
+ * PARCIterator *iterator = parcTreeMap_CreateKeyIterator(myTreeMap);
+ *
+ * while (parcIterator_HasNext(iterator)) {
+ * PARCObject *object = parcIterator_Next(iterator);
+ * }
+ *
+ * parcIterator_Release(&iterator);
+ * }
+ * @endcode
+ */
+PARCIterator *parcTreeMap_CreateKeyIterator(PARCTreeMap *tree);
+
+/**
+ * Create a new instance of PARCIterator that iterates through the values of the specified `PARCTreeMap`.
+ * The returned iterator must be released via {@link parcIterator_Release}.
+ *
+ * @param [in] hashMap A pointer to a valid `PARCTreeMap`.
+ *
+ * @see parcIterator_Release
+ * Example:
+ * @code
+ * {
+ * PARCIterator *iterator = parcTreeMap_CreateValueIterator(myTreeMap);
+ *
+ * while (parcIterator_HasNext(iterator)) {
+ * PARCObject *object = parcIterator_Next(iterator);
+ * }
+ *
+ * parcIterator_Release(&iterator);
+ * }
+ * @endcode
+ */
+PARCIterator *parcTreeMap_CreateValueIterator(PARCTreeMap *tree);
+
+/**
+ * Create a new instance of PARCIterator that iterates through the KeyValue elements of the specified `PARCTreeMap`.
+ * The returned iterator must be released via {@link parcIterator_Release}.
+ *
+ * @param [in] hashMap A pointer to a valid `PARCTreeMap`.
+ *
+ * @see parcIterator_Release
+ * Example:
+ * @code
+ * {
+ * PARCIterator *iterator = parcTreeMap_CreateKeyValueIterator(myTreeMap);
+ *
+ * while (parcIterator_HasNext(iterator)) {
+ * PARCObject *object = parcIterator_Next(iterator);
+ * }
+ *
+ * parcIterator_Release(&iterator);
+ * }
+ * @endcode
+ */
+PARCIterator *parcTreeMap_CreateKeyValueIterator(PARCTreeMap *tree);
+#endif // libparc_parc_TreeMap_h
diff --git a/libparc/parc/algol/parc_TreeRedBlack.c b/libparc/parc/algol/parc_TreeRedBlack.c
new file mode 100755
index 00000000..2d772555
--- /dev/null
+++ b/libparc/parc/algol/parc_TreeRedBlack.c
@@ -0,0 +1,781 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <parc/algol/parc_TreeRedBlack.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#define RED 1
+#define BLACK 0
+
+struct redblack_node;
+typedef struct redblack_node Node;
+
+struct redblack_node {
+ Node *left_child;
+ Node *right_child;
+ Node *parent;
+ void *key;
+ void *value;
+ int color;
+};
+
+struct parc_tree_redblack {
+ Node *root;
+ Node *nil;
+ int size;
+ PARCTreeRedBlack_KeyCompare *keyCompare;
+ PARCTreeRedBlack_KeyFree *keyFree;
+ PARCTreeRedBlack_KeyCopy *keyCopy;
+ PARCTreeRedBlack_ValueFree *valueFree;
+ PARCTreeRedBlack_ValueEquals *valueEquals;
+ PARCTreeRedBlack_ValueCopy *valueCopy;
+};
+
+typedef void (rbRecursiveFunc)(Node *node, void *data);
+
+static void
+_rbNodeFree(PARCTreeRedBlack *tree, Node *node)
+{
+ if (tree->keyFree != NULL) {
+ tree->keyFree(&(node->key));
+ }
+ if (tree->valueFree != NULL) {
+ tree->valueFree(&(node->value));
+ }
+ parcMemory_Deallocate((void **) &node);
+}
+
+static void
+_rbNodeFreeRecursive(PARCTreeRedBlack *tree, Node *node)
+{
+ if (node->left_child != tree->nil) {
+ _rbNodeFreeRecursive(tree, node->left_child);
+ }
+ if (node->right_child != tree->nil) {
+ _rbNodeFreeRecursive(tree, node->right_child);
+ }
+ // We descended on both branches, now free myself.
+ _rbNodeFree(tree, node);
+ tree->size--;
+}
+
+// Run a function on all nodes in the tree, in order
+static void
+_rbNodeRecursiveRun(PARCTreeRedBlack *tree, Node *node, rbRecursiveFunc *func, void *data)
+{
+ if (node->left_child != tree->nil) {
+ _rbNodeRecursiveRun(tree, node->left_child, func, data);
+ }
+ func(node, data);
+ if (node->right_child != tree->nil) {
+ _rbNodeRecursiveRun(tree, node->right_child, func, data);
+ }
+}
+
+/**
+ * Create a node
+ * Set the parent and children to tree->nil.
+ * If we are creating the nil node this might leave garbage there (if not preset to NULL).
+ */
+static Node *
+_rbNodeCreate(PARCTreeRedBlack *tree, int color)
+{
+ Node *node = parcMemory_AllocateAndClear(sizeof(Node));
+ assertNotNull(node, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(Node));
+ node->color = color;
+ node->left_child = tree->nil;
+ node->right_child = tree->nil;
+ node->parent = tree->nil;
+ return node;
+}
+
+static void
+_rbNodeSetColor(Node *node, uint8_t color)
+{
+ node->color = color;
+}
+
+static int
+_rbNodeColor(const Node *node)
+{
+ return node->color;
+}
+
+static int
+_rbNodeIsEqual(const PARCTreeRedBlack *tree, const Node *node, const void *key)
+{
+ return (tree->keyCompare(node->key, key) == 0);
+}
+
+static int
+_rbNodeIsGreaterThan(const PARCTreeRedBlack *tree, const Node *node, const void *key)
+{
+ return (tree->keyCompare(node->key, key) > 0);
+}
+
+static void
+_rbNodeUpdate(PARCTreeRedBlack *tree, Node *treeNode, Node *newNode)
+{
+ // Free old values
+ if (tree->keyFree != NULL) {
+ tree->keyFree(&(treeNode->key));
+ }
+ if (tree->valueFree != NULL) {
+ tree->valueFree(&(treeNode->value));
+ }
+ treeNode->key = newNode->key;
+ treeNode->value = newNode->value;
+ parcMemory_Deallocate((void **) &newNode);
+}
+
+static void
+_rbNodeRotateLeft(PARCTreeRedBlack *tree, Node *node)
+{
+ Node *subroot = node->right_child;
+ node->right_child = subroot->left_child;
+ if (node->right_child != tree->nil) {
+ node->right_child->parent = node;
+ }
+
+ subroot->parent = node->parent;
+ if (tree->root == node) {
+ tree->root = subroot;
+ } else {
+ if (subroot->parent->left_child == node) {
+ // node was a left child
+ subroot->parent->left_child = subroot;
+ } else {
+ // node was a right child
+ subroot->parent->right_child = subroot;
+ }
+ }
+
+ subroot->left_child = node;
+ node->parent = subroot;
+}
+
+static void
+_rbNodeRotateRight(PARCTreeRedBlack *tree, Node *node)
+{
+ Node *subroot = node->left_child;
+ node->left_child = subroot->right_child;
+ if (node->left_child != tree->nil) {
+ node->left_child->parent = node;
+ }
+
+ subroot->parent = node->parent;
+ if (tree->root == node) {
+ tree->root = subroot;
+ } else {
+ if (subroot->parent->left_child == node) {
+ // node was a left child
+ subroot->parent->left_child = subroot;
+ } else {
+ // node was a right child
+ subroot->parent->right_child = subroot;
+ }
+ }
+
+ subroot->right_child = node;
+ node->parent = subroot;
+}
+
+static void
+_rbNodeFix(PARCTreeRedBlack *tree, Node *startNode)
+{
+ Node *node = startNode;
+ Node *uncle;
+ while (_rbNodeColor(node->parent) == RED) {
+ if (node->parent->parent->left_child == node->parent) {
+ uncle = node->parent->parent->right_child;
+ if (_rbNodeColor(uncle) == RED) {
+ // My dad and uncle are red. Switch dad to black.
+ // Switch grandpa to red and start there.
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(uncle, BLACK);
+ _rbNodeSetColor(node->parent->parent, RED);
+ node = node->parent->parent;
+ } else {
+ if (node->parent->right_child == node) {
+ node = node->parent;
+ _rbNodeRotateLeft(tree, node);
+ }
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(node->parent->parent, RED);
+ _rbNodeRotateRight(tree, node->parent->parent);
+ }
+ } else {
+ uncle = node->parent->parent->left_child;
+ if (_rbNodeColor(uncle) == RED) {
+ // My dad and uncle are red. Switch dad to black.
+ // Switch grandpa to red and start there.
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(uncle, BLACK);
+ _rbNodeSetColor(node->parent->parent, RED);
+ node = node->parent->parent;
+ } else {
+ if (node->parent->left_child == node) {
+ node = node->parent;
+ _rbNodeRotateRight(tree, node);
+ }
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(node->parent->parent, RED);
+ _rbNodeRotateLeft(tree, node->parent->parent);
+ }
+ }
+ }
+ _rbNodeSetColor(tree->root, BLACK);
+}
+
+static void
+_rbNodeFixDelete(PARCTreeRedBlack *tree, Node *node)
+{
+ Node *fixNode;
+
+ while ((node != tree->root) && (_rbNodeColor(node) == BLACK)) {
+ if (node == node->parent->left_child) {
+ fixNode = node->parent->right_child;
+ if (_rbNodeColor(fixNode) == RED) {
+ _rbNodeSetColor(fixNode, BLACK);
+ _rbNodeSetColor(node->parent, RED);
+ _rbNodeRotateLeft(tree, node->parent);
+ fixNode = node->parent->right_child;
+ }
+ if ((_rbNodeColor(fixNode->left_child) == BLACK) &&
+ (_rbNodeColor(fixNode->right_child) == BLACK)) {
+ _rbNodeSetColor(fixNode, RED);
+ node = node->parent;
+ } else {
+ if (_rbNodeColor(fixNode->right_child) == BLACK) {
+ _rbNodeSetColor(fixNode->left_child, BLACK);
+ _rbNodeSetColor(fixNode, RED);
+ _rbNodeRotateRight(tree, fixNode);
+ fixNode = node->parent->right_child;
+ }
+ _rbNodeSetColor(fixNode, _rbNodeColor(node->parent));
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(fixNode->right_child, BLACK);
+ _rbNodeRotateLeft(tree, node->parent);
+ node = tree->root;
+ }
+ } else {
+ fixNode = node->parent->left_child;
+ if (_rbNodeColor(fixNode) == RED) {
+ _rbNodeSetColor(fixNode, BLACK);
+ _rbNodeSetColor(node->parent, RED);
+ _rbNodeRotateRight(tree, node->parent);
+ fixNode = node->parent->left_child;
+ }
+ if ((_rbNodeColor(fixNode->left_child) == BLACK) &&
+ (_rbNodeColor(fixNode->right_child) == BLACK)) {
+ _rbNodeSetColor(fixNode, RED);
+ node = node->parent;
+ } else {
+ if (_rbNodeColor(fixNode->left_child) == BLACK) {
+ _rbNodeSetColor(fixNode->right_child, BLACK);
+ _rbNodeSetColor(fixNode, RED);
+ _rbNodeRotateLeft(tree, fixNode);
+ fixNode = node->parent->left_child;
+ }
+ _rbNodeSetColor(fixNode, _rbNodeColor(node->parent));
+ _rbNodeSetColor(node->parent, BLACK);
+ _rbNodeSetColor(fixNode->left_child, BLACK);
+ _rbNodeRotateRight(tree, node->parent);
+ node = tree->root;
+ }
+ }
+ }
+
+ _rbNodeSetColor(node, BLACK);
+}
+
+// Remove the node from the tree.
+// The node must be part of a tree (with parents and children)
+static void
+_rbNodeRemove(PARCTreeRedBlack *tree, Node *node)
+{
+ Node *fixupNode;
+ int deleteNodeColor = _rbNodeColor(node);
+ if (node->left_child == tree->nil) {
+ if (node->right_child == tree->nil) {
+ // ---- We have no children ----
+ if (tree->root == node) {
+ tree->root = tree->nil;
+ } else {
+ if (node->parent->left_child == node) {
+ node->parent->left_child = tree->nil;
+ } else {
+ node->parent->right_child = tree->nil;
+ }
+ }
+ fixupNode = tree->nil;
+ fixupNode->parent = node->parent;
+ } else {
+ // ---- We only have right child, move up ----
+ if (tree->root == node) {
+ tree->root = node->right_child;
+ } else {
+ if (node->parent->left_child == node) {
+ node->parent->left_child = node->right_child;
+ } else {
+ node->parent->right_child = node->right_child;
+ }
+ }
+ fixupNode = node->right_child;
+ node->right_child->parent = node->parent;
+ }
+ } else {
+ if (node->right_child == tree->nil) {
+ // ---- We only have left child, move up ----
+ if (tree->root == node) {
+ tree->root = node->left_child;
+ } else {
+ if (node->parent->left_child == node) {
+ node->parent->left_child = node->left_child;
+ } else {
+ node->parent->right_child = node->left_child;
+ }
+ }
+ node->left_child->parent = node->parent;
+ fixupNode = node->left_child;
+ } else {
+ // ---- We have 2 children, move our successor to our location ----
+ Node *successor = node->right_child;
+ while (successor->left_child != tree->nil) {
+ successor = successor->left_child;
+ }
+ deleteNodeColor = _rbNodeColor(successor);
+
+ // Remove successor, it has no left child
+ if (successor == successor->parent->left_child) {
+ successor->parent->left_child = successor->right_child;
+ } else {
+ successor->parent->right_child = successor->right_child;
+ }
+ successor->right_child->parent = successor->parent;
+
+ fixupNode = successor->right_child;
+
+ if (node->parent == tree->nil) {
+ tree->root = successor;
+ } else if (node->parent->left_child == node) {
+ node->parent->left_child = successor;
+ } else {
+ node->parent->right_child = successor;
+ }
+ successor->parent = node->parent;
+ successor->left_child = node->left_child;
+ node->left_child->parent = successor;
+ successor->right_child = node->right_child;
+ node->right_child->parent = successor;
+
+ _rbNodeSetColor(successor, _rbNodeColor(node));
+
+ if (successor->parent == tree->nil) {
+ tree->root = successor;
+ }
+ }
+ }
+ tree->size--;
+
+ // Fix the red-blackness
+ if (deleteNodeColor == BLACK) {
+ _rbNodeFixDelete(tree, fixupNode);
+ }
+}
+
+
+PARCTreeRedBlack *
+parcTreeRedBlack_Create(PARCTreeRedBlack_KeyCompare *keyCompare,
+ PARCTreeRedBlack_KeyFree *keyFree,
+ PARCTreeRedBlack_KeyCopy *keyCopy,
+ PARCTreeRedBlack_ValueEquals *valueEquals,
+ PARCTreeRedBlack_ValueFree *valueFree,
+ PARCTreeRedBlack_ValueCopy *valueCopy)
+{
+ assertNotNull(keyCompare, "We need a key compare function");
+ PARCTreeRedBlack *tree = parcMemory_AllocateAndClear(sizeof(PARCTreeRedBlack));
+ assertNotNull(tree, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCTreeRedBlack));
+ tree->nil = _rbNodeCreate(tree, BLACK);
+ tree->nil->left_child = tree->nil;
+ tree->nil->right_child = tree->nil;
+ tree->nil->parent = tree->nil;
+ tree->root = tree->nil;
+ tree->keyCompare = keyCompare;
+ tree->keyFree = keyFree;
+ tree->keyCopy = keyCopy;
+ tree->valueEquals = valueEquals;
+ tree->valueFree = valueFree;
+ tree->valueCopy = valueCopy;
+ tree->size = 0;
+ return tree;
+}
+
+void
+parcTreeRedBlack_Destroy(PARCTreeRedBlack **treePointer)
+{
+ assertNotNull(treePointer, "pointer to pointer to tree can't be null");
+ assertNotNull(*treePointer, "pointer to tree can't be null");
+
+ if ((*treePointer)->size > 0) {
+ // If we have any elements in the tree, free them
+ _rbNodeFreeRecursive(*treePointer, (*treePointer)->root);
+ }
+
+ // Free the nil element
+ parcMemory_Deallocate((void **) &((*treePointer)->nil));
+
+ parcMemory_Deallocate((void **) treePointer);
+ *treePointer = NULL;
+}
+
+void
+parcTreeRedBlack_Insert(PARCTreeRedBlack *tree, void *key, void *value)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ assertNotNull(key, "Key can't be NULL");
+ assertNotNull(value, "Value can't be NULL");
+
+ Node *newNode = _rbNodeCreate(tree, RED);
+ Node *parent = tree->nil;
+ Node *node;
+
+ // Set the value for the created node
+ newNode->key = key;
+ newNode->value = value;
+
+ // Start at the top
+ node = tree->root;
+
+ // Let's get to the bottom of the tree to insert.
+ while (node != tree->nil) {
+ parent = node;
+ if (_rbNodeIsEqual(tree, node, key)) {
+ // We're trying to insert the same value
+ _rbNodeUpdate(tree, node, newNode);
+ return;
+ } else {
+ if (_rbNodeIsGreaterThan(tree, node, key)) {
+ // The key is smaller
+ node = node->left_child;
+ } else {
+ node = node->right_child;
+ }
+ }
+ }
+
+ // We're at the bottom.
+ // node is nil (a leaf)
+ newNode->parent = parent;
+ if (parent == tree->nil) {
+ // nil is our parent, we are the root
+ tree->root = newNode;
+ } else {
+ if (_rbNodeIsGreaterThan(tree, parent, key)) {
+ parent->left_child = newNode;
+ } else {
+ parent->right_child = newNode;
+ }
+ }
+
+ // We have inserted one node.
+ tree->size++;
+
+ // We have a correct tree. But we need to regain the red-black property.
+ _rbNodeFix(tree, newNode);
+
+}
+
+// Return value
+void *
+parcTreeRedBlack_Get(PARCTreeRedBlack *tree, const void *key)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+
+ Node *node = tree->root;
+
+ // Let's get to the bottom of the tree to insert.
+ while (node != tree->nil) {
+ if (_rbNodeIsEqual(tree, node, key)) {
+ // We found the node, return
+ return node->value;
+ } else {
+ if (_rbNodeIsGreaterThan(tree, node, key)) {
+ node = node->left_child;
+ } else {
+ node = node->right_child;
+ }
+ }
+ }
+ return NULL;
+}
+
+// Return value, remove from tree
+void *
+parcTreeRedBlack_Remove(PARCTreeRedBlack *tree, const void *key)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ assertNotNull(key, "Key can't be NULL");
+
+ Node *node = tree->root;
+
+ // Let's get to the bottom of the tree to insert.
+ while (node != tree->nil) {
+ if (_rbNodeIsEqual(tree, node, key)) {
+ _rbNodeRemove(tree, node);
+ void *value = node->value;
+ if (tree->keyFree != NULL) {
+ tree->keyFree(&node->key);
+ }
+ parcMemory_Deallocate((void **) &node);
+ return value;
+ } else {
+ if (_rbNodeIsGreaterThan(tree, node, key)) {
+ node = node->left_child;
+ } else {
+ node = node->right_child;
+ }
+ }
+ }
+
+ // We didn't find the node
+
+ return NULL;
+}
+
+// remove from tree and destroy
+void
+parcTreeRedBlack_RemoveAndDestroy(PARCTreeRedBlack *tree, const void *key)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ assertNotNull(key, "Key can't be NULL");
+
+ Node *node = tree->root;
+ // Let's get to the bottom of the tree to insert.
+ while (node != tree->nil) {
+ if (_rbNodeIsEqual(tree, node, key)) {
+ _rbNodeRemove(tree, node);
+ _rbNodeFree(tree, node);
+ return;
+ } else {
+ if (_rbNodeIsGreaterThan(tree, node, key)) {
+ node = node->left_child;
+ } else {
+ node = node->right_child;
+ }
+ }
+ }
+}
+
+void *
+parcTreeRedBlack_LastKey(const PARCTreeRedBlack *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ Node *node = tree->root;
+
+ if (tree->size == 0) {
+ // We don't have any entries
+ return NULL;
+ }
+
+ // Let's get to the bottom right of the tree to find the largest
+ while (node->right_child != tree->nil) {
+ node = node->right_child;
+ }
+
+ return node->key;
+}
+
+void *
+parcTreeRedBlack_FirstKey(const PARCTreeRedBlack *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ Node *node = tree->root;
+
+
+ if (tree->size == 0) {
+ // We don't have any entries
+ return NULL;
+ }
+
+ // Let's get to the bottom left of the tree to find the smallest
+ while (node->left_child != tree->nil) {
+ node = node->left_child;
+ }
+
+ return node->key;
+}
+
+size_t
+parcTreeRedBlack_Size(const PARCTreeRedBlack *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+
+ return tree->size;
+}
+
+static void
+_rbGetKeys(Node *node, void *data)
+{
+ PARCArrayList *list = (PARCArrayList *) data;
+ parcArrayList_Add(list, node->key);
+}
+
+PARCArrayList *
+parcTreeRedBlack_Keys(const PARCTreeRedBlack *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+
+ PARCArrayList *keys = parcArrayList_Create(NULL);
+
+ if (tree->size > 0) {
+ _rbNodeRecursiveRun((PARCTreeRedBlack *) tree, tree->root, _rbGetKeys, keys);
+ }
+ return keys;
+}
+
+static void
+_rbGetValues(Node *node, void *data)
+{
+ PARCArrayList *list = (PARCArrayList *) data;
+ parcArrayList_Add(list, node->value);
+}
+
+PARCArrayList *
+parcTreeRedBlack_Values(const PARCTreeRedBlack *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+
+ PARCArrayList *values = parcArrayList_Create(NULL);
+
+ if (tree->size > 0) {
+ _rbNodeRecursiveRun((PARCTreeRedBlack *) tree, tree->root, _rbGetValues, values);
+ }
+ return values;
+}
+
+int
+parcTreeRedBlack_Equals(const PARCTreeRedBlack *tree1, const PARCTreeRedBlack *tree2)
+{
+ assertNotNull(tree1, "Tree can't be NULL");
+ assertNotNull(tree2, "Tree can't be NULL");
+
+ int ret = 1;
+
+ PARCArrayList *keys1 = parcTreeRedBlack_Keys(tree1);
+ PARCArrayList *keys2 = parcTreeRedBlack_Keys(tree2);
+ size_t length1 = parcArrayList_Size(keys1);
+ size_t length2 = parcArrayList_Size(keys2);
+
+ if (length1 == length2) {
+ for (size_t i = 0; i < length1; i++) {
+ if (tree1->keyCompare(parcArrayList_Get(keys1, i), parcArrayList_Get(keys2, i)) != 0) {
+ ret = 0;
+ break;
+ }
+ }
+ if (ret != 0) {
+ PARCArrayList *values1 = parcTreeRedBlack_Values(tree1);
+ PARCArrayList *values2 = parcTreeRedBlack_Values(tree2);
+ size_t length1 = parcArrayList_Size(values1);
+ size_t length2 = parcArrayList_Size(values2);
+ if (length1 == length2) {
+ for (size_t i = 0; i < length1; i++) {
+ void *value1 = parcArrayList_Get(values1, i);
+ void *value2 = parcArrayList_Get(values2, i);
+ if (tree1->valueEquals != NULL) {
+ if (tree1->valueEquals(value1, value2) == 0) {
+ ret = 0;
+ break;
+ }
+ } else {
+ if (value1 != value2) {
+ ret = 0;
+ break;
+ }
+ }
+ }
+ }
+ parcArrayList_Destroy(&values1);
+ parcArrayList_Destroy(&values2);
+ }
+ } else {
+ ret = 0;
+ }
+
+ parcArrayList_Destroy(&keys1);
+ parcArrayList_Destroy(&keys2);
+ return ret;
+}
+
+
+/*
+ * This is a simple implementation of Copy that goes through the list of keys and values.
+ */
+PARCTreeRedBlack *
+parcTreeRedBlack_Copy(const PARCTreeRedBlack *source_tree)
+{
+ assertNotNull(source_tree, "Tree can't be NULL");
+
+ void *key_source;
+ void *key_copy;
+ void *value_source;
+ void *value_copy;
+
+ PARCTreeRedBlack *tree_copy = parcTreeRedBlack_Create(source_tree->keyCompare,
+ source_tree->keyFree,
+ source_tree->keyCopy,
+ source_tree->valueEquals,
+ source_tree->valueFree,
+ source_tree->valueCopy);
+
+ PARCArrayList *keys = parcTreeRedBlack_Keys(source_tree);
+ PARCArrayList *values = parcTreeRedBlack_Values(source_tree);
+
+ size_t total_keys = parcArrayList_Size(keys);
+
+ for (size_t i = 0; i < total_keys; i++) {
+ key_source = parcArrayList_Get(keys, i);
+ value_source = parcArrayList_Get(values, i);
+
+ if (source_tree->keyCopy != NULL) {
+ key_copy = source_tree->keyCopy(key_source);
+ } else {
+ key_copy = key_source;
+ }
+
+ if (source_tree->valueCopy != NULL) {
+ value_copy = source_tree->valueCopy(value_source);
+ } else {
+ value_copy = value_source;
+ }
+
+ parcTreeRedBlack_Insert(tree_copy, key_copy, value_copy);
+ }
+
+ parcArrayList_Destroy(&keys);
+ parcArrayList_Destroy(&values);
+
+ return tree_copy;
+}
diff --git a/libparc/parc/algol/parc_TreeRedBlack.h b/libparc/parc/algol/parc_TreeRedBlack.h
new file mode 100755
index 00000000..52d4af36
--- /dev/null
+++ b/libparc/parc/algol/parc_TreeRedBlack.h
@@ -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.
+ */
+
+/**
+ * @file parc_TreeRedBlack.h
+ * @ingroup datastructures
+ * @brief A red-black tree is a type of self-balancing binary search tree,
+ * a data structure used in computer science, typically used to implement associative arrays.
+ *
+ */
+#ifndef libparc_parc_TreeRedBlack_h
+#define libparc_parc_TreeRedBlack_h
+
+#include <stdlib.h>
+#include <parc/algol/parc_ArrayList.h>
+
+struct parc_tree_redblack;
+typedef struct parc_tree_redblack PARCTreeRedBlack;
+
+/**
+ * Compare two keys (signum)
+ *
+ * This is the definition of a function that takes two keys and compares them.
+ * It is a signum function. A user of the RedBlack tree will provide this function on creation
+ * so the tree can perform it's operations.
+ *
+ * @param [in] key1 The first key to compare
+ * @param [in] key2 The second key to compare
+ * @return A signum comparison. negative if key 1 is smaller, 0 if key1 == key2, greater than 0 if key1 is bigger.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef int (PARCTreeRedBlack_KeyCompare)(const void *key1, const void *key2);
+
+/**
+ * Compare two values for equality
+ *
+ * This is a function definiton for a function that compares two values in a `PARCTreeRedBlack`.
+ * If the values are equal it will return true. If they are not it will return false.
+ * A function of this type will be given on the creation of the `PARCTreeRedBlack`. It will be used by the tree
+ * to test equality.
+ *
+ * @param [in] value1 The first value to compare
+ * @param [in] value2 The second value to compare
+ * @return TRUE if the values are considered equal, FALSE if they are not
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef bool (PARCTreeRedBlack_ValueEquals)(const void *value1, const void *value2);
+
+/**
+ * A function to free a value pointer
+ *
+ * This is a function definition for a function to free a value in the `PARCTreeRedBlack`. The function should
+ * free/destroy the value when called. A function of this type will be passed to the `PARCTreeRedBlack` on
+ * creation. It will be used to destroy values when needed.
+ *
+ * @param [in,out] value A pointer to a pointer to a value to be freed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef void (PARCTreeRedBlack_ValueFree)(void **value);
+
+/**
+ * A function to free a key pointer
+ *
+ * This is a function definition for a function to free a key in the `PARCTreeRedBlack`. The function should
+ * free/destroy the key when called. A function of this type will be passed to the `PARCTreeRedBlack` on
+ * creation. It will be used to destroy keys when needed.
+ *
+ * @param [in,out] key A pointer to a pointer to a key to be freed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef void (PARCTreeRedBlack_KeyFree)(void **key);
+
+/**
+ * Create a copy of a key.
+ *
+ * This must be a real copy! (allocating new memory)
+ *
+ * This function should create a copy of the key. The copy must pass an equality test to the original key.
+ * If this function retuns NULL, the tree copy will fail (and return NULL)
+ *
+ * @param [in] key A pointer to the key to be copied
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new key instance
+ *
+ */
+typedef void * (PARCTreeRedBlack_KeyCopy)(const void *key);
+
+/**
+ * Create a copy of a value
+ *
+ * This must be a real copy! (new memory allocated)
+ *
+ * This function should create a copy of the value. The copy must pass an equality test to the original value.
+ * If this function retuns NULL, the tree copy will fail (and return NULL)
+ *
+ * @param [in] value A pointer to the value to be copied
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new value instance
+ *
+ */
+typedef void * (PARCTreeRedBlack_ValueCopy)(const void *value);
+
+/**
+ * Create a `PARCTreeRedBlack`
+ *
+ * Create a RedBlack Tree. You must provide a key compare function.
+ * The valueEquals function will be used to compare 2 trees. If you do not provide such a function
+ * the values will be compared directly.
+ * The keyFree and valueFree functions are optional but highly encouraged. They will be used on
+ * destruction of the tree on any remaining elements. They are also used on deletion of elements.
+ *
+ * @param [in] keyCompare A function to compare keys (required)
+ * @param [in] keyFree A function to free Keys (may be NULL)
+ * @param [in] keyCopy A function to copy Keys (may be NULL)
+ * @param [in] valueEquals A function to test value equality (may be NULL)
+ * @param [in] valueFree A function to free Values (may be NULL)
+ * @param [in] valueCopy A function to free Keys (may be NULL)
+ * @return NULL Error allocating memory
+ * @return Non-NULL An initialized RedBlack tree
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCTreeRedBlack *parcTreeRedBlack_Create(PARCTreeRedBlack_KeyCompare *keyCompare,
+ PARCTreeRedBlack_KeyFree *keyFree,
+ PARCTreeRedBlack_KeyCopy *keyCopy,
+ PARCTreeRedBlack_ValueEquals *valueEquals,
+ PARCTreeRedBlack_ValueFree *valueFree,
+ PARCTreeRedBlack_ValueCopy *valueCopy);
+
+/**
+ * Destroy a `PARCTreeRedBlack`
+ *
+ * Destroy a `PARCTreeRedBlack`, free all the memory.
+ * All remaining keys and values will be freed with the respective free functions.
+ *
+ * @param [in,out] treePointer A pointer to a pointer to the `PARCTreeRedBlack` to be destroyed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcTreeRedBlack_Destroy(PARCTreeRedBlack **treePointer);
+
+/**
+ * Insert a value into the `PARCTreeRedBlack`.
+ *
+ * Insert a value into the `PARCTreeRedBlack`.
+ * If the key exists in the tree then the new value will replace the old value.
+ * The old key and value will be freed using the provided free functions.
+ * The tree will take ownership of the key and value. They can't be NULL.
+ *
+ * @param [in,out] tree A pointer to an initialized `PARCTreeRedBlack`.
+ * @param [in] key A pointer to a key - This may not be NULL.
+ * @param [in] value A pointer to a value - This may not be NULL.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcTreeRedBlack_Insert(PARCTreeRedBlack *tree, void *key, void *value);
+
+/**
+ * Get a value into the `PARCTreeRedBlack`.
+ *
+ * Get a value from a `PARCTreeRedBlack`.
+ * If the key is not found in the tree NULL is returned.
+ * The returned value will still be owned by the tree.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeRedBlack`.
+ * @param [in] key A pointer to a key (The tree will not own this).
+ * @return A pointer to a value. You do not own this value (it's still in the tree).
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcTreeRedBlack_Get(PARCTreeRedBlack *tree, const void *key);
+
+/**
+ * Get the first (smallest) key from a `PARCTreeRedBlack`.
+ *
+ * Get the first (smallest) key from a `PARCTreeRedBlack`.
+ * The returned key will still be owned by the tree.
+ * If the tree is empty the function will return NULL.
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeRedBlack`.
+ * @return A pointer to the smallest key. You do not own this value (it's still in the tree).
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcTreeRedBlack_FirstKey(const PARCTreeRedBlack *tree);
+
+/**
+ * Get the last (largest) key from a `PARCTreeRedBlack`.
+ *
+ * Get the last (largest) key from a `PARCTreeRedBlack`.
+ * The returned key will still be owned by the tree.
+ * If the tree is empty the function will return NULL
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeRedBlack`.
+ * @return A pointer to the smallest key. You do not own this value (it's still in the tree).
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcTreeRedBlack_LastKey(const PARCTreeRedBlack *tree);
+
+/**
+ * Remove a value (and key) from a `PARCTreeRedBlack`.
+ *
+ * Remove a value from a `PARCTreeRedBlack`. The value (and key) will no longer be in the tree.
+ * The (internal) key will be freed. The provided key will not be modified.
+ * The value associated with the key will be returned. You will own this value.
+ * If the key is not found in the tree NULL is returned.
+ *
+ * @param [in,out] tree A pointer to an initialized `PARCTreeRedBlack`.
+ * @param [in] key A pointer to a key (The tree will not own this).
+ * @return A pointer to a value. You will now own this value.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void *parcTreeRedBlack_Remove(PARCTreeRedBlack *tree, const void *key);
+
+/**
+ * Remove and destroy a value (and key) from a `PARCTreeRedBlack`.
+ *
+ * Delete a value from a `PARCTreeRedBlack`. The value (and key) will no longer be in the tree.
+ * The value and key will be freed by the tree. The provided key will not be modified.
+ *
+ * @param [in,out] tree A pointer to an initialized `PARCTreeRedBlack`.
+ * @param [in] key A pointer to a key (The tree will not own this).
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcTreeRedBlack_RemoveAndDestroy(PARCTreeRedBlack *tree, const void *key);
+
+/**
+ * Get the size of a `PARCTreeRedBlack`.
+ *
+ * Return the size of the tree (number of elements).
+ *
+ * @param [in] tree A pointer to an initialized `PARCTreeRedBlack`.
+ * @return size of the tree (number of elements).
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcTreeRedBlack_Size(const PARCTreeRedBlack *tree);
+
+/**
+ * Get an ArrayList of the keys in this tree
+ *
+ * Get a list of the keys from this `PARCTreeRedBlack`. All of these keys will be valid keys in the `PARCTreeRedBlack`.
+ * The caller will own the list of keys and should destroy it when done. The caller will not own
+ * the keys themselves. Destroying the {@link PARCArrayList} should be enough.
+ * Note that if the tree is modified or destroyed the key pointers might no longer point to valid keys.
+ * The list of keys will be sorted (as defined by the key compare function, smallest first)
+ *
+ * @param [in] tree A pointer to a `PARCTreeRedBlack`.
+ * @return A list of (pointers to) keys.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCArrayList *parcTreeRedBlack_Keys(const PARCTreeRedBlack *tree);
+
+/**
+ * Get an ArrayList of the values in this `PARCTreeRedBlack`.
+ *
+ * Get a list of the values from this tree. All of these values will be valid in the `PARCTreeRedBlack`.
+ * The caller will own the list of values and should destroy it when done. The caller will not own
+ * the values themselves. Destroying the {@link PARCArrayList} should be enough.
+ * Note that if the tree is modified or destroyed the value pointers might no longer point to valid values.
+ * The list of values will be sorted by key (as defined by the key compare function, smallest first).
+ *
+ * @param [in] tree A pointer to a `PARCTreeRedBlack`.
+ * @return A list of (pointers to) values.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCArrayList *parcTreeRedBlack_Values(const PARCTreeRedBlack *tree);
+
+/**
+ * Calculate if two `PARCTreeRedBlack`s are equal
+ *
+ * Compare 2 `PARCTreeRedBlack` for equality.
+ * Two trees are equal if they have the same keys associated with the same values. The values
+ * will be compared using the valueEquals function provided on create. If this function was not
+ * provided it will compare the actual values.
+ *
+ * @param [in] tree1 A pointer to a `PARCTreeRedBlack`.
+ * @param [in] tree2 A pointer to another `PARCTreeRedBlack`.
+ * @return true if the trees are equal, zero otherwise
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int parcTreeRedBlack_Equals(const PARCTreeRedBlack *tree1, const PARCTreeRedBlack *tree2);
+
+/**
+ * Copy a RedBlack Tree
+ *
+ * Crete a copy of a RedBlack Tree.
+ * This will create a completely new tree. It will copy every key and every value using the Copy functions
+ * provided at tree creation. If these functions are NULL then the numeric values will be copied directly.
+ *
+ * @param [in] source_tree A pointer to a `PARCTreeRedBlack` to be copied
+ * @return NULL Error copying the tree.
+ * @return Non-NULL A copy of the `PARCTreeRedBlack`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTreeRedBlack * source_tree = parcTreeRedBlack_Create(.....);
+ *
+ * ... operations on tree ...
+ *
+ * PARCTreeRedBlack * tree_copy = parcTreeRedBlack_Copy(source_tree);
+ *
+ * ... operations on tree ...
+ *
+ * parcTreeRedBlack_Destroy(&source_tree);
+ * parcTreeRedBlack_Destroy(&tree_copy);
+ * }
+ * @endcode
+ */
+PARCTreeRedBlack *parcTreeRedBlack_Copy(const PARCTreeRedBlack *source_tree);
+#endif // libparc_parc_TreeRedBlack_h
diff --git a/libparc/parc/algol/parc_URI.c b/libparc/parc/algol/parc_URI.c
new file mode 100644
index 00000000..172468d8
--- /dev/null
+++ b/libparc/parc/algol/parc_URI.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#include <parc/algol/parc_URI.h>
+
+#include <parc/algol/parc_URIPath.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+char *sub_delims = "!$&'()*+,;=";
+char *gen_delims = ":/?#[]@";
+
+#define isSubDelims(c) (c != 0 && strchr(sub_delims, c) != NULL)
+#define isGenDelims(c) (c != 0 && strchr(gen_delims, c) != NULL)
+#define isDigit(c) (c >= '0' && c <= '9')
+#define isAlpha(c) (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+
+#define isUnreserved(c) (isAlpha(c) || isDigit(c) || c == '-' || c == '.' || c == '_' || c == '~')
+#define isReserved(c) (isGenDelims(c) || isSubDelims(c))
+#define isPchar(c) (isUnreserved(c) || isSubDelims(c) || c == ':' || c == '@')
+
+struct parc_uri {
+ char *scheme;
+ char *authority;
+ PARCURIPath *path;
+ char *query;
+ char *fragment;
+};
+
+static void
+_parcURI_Finalize(PARCURI **uriPtr)
+{
+ assertNotNull(uriPtr, "Parameter must be a non-null pointer to a pointer to a PARCURI instance.");
+
+ PARCURI *uri = *uriPtr;
+
+ if (uri->scheme != NULL) {
+ parcMemory_Deallocate((void **) &uri->scheme);
+ }
+
+ if (uri->authority != NULL) {
+ parcMemory_Deallocate((void **) &(uri->authority));
+ }
+
+ if (uri->path) {
+ parcURIPath_Release(&uri->path);
+ }
+
+ if (uri->query != NULL) {
+ parcMemory_Deallocate((void **) &(uri->query));
+ }
+
+ if (uri->fragment != NULL) {
+ parcMemory_Deallocate((void **) &(uri->fragment));
+ }
+}
+
+parcObject_ExtendPARCObject(PARCURI, _parcURI_Finalize, parcURI_Copy, parcURI_ToString, parcURI_Equals, NULL, NULL, NULL);
+
+PARCURI *
+parcURI_Create(void)
+{
+ PARCURI *result = parcObject_CreateAndClearInstance(PARCURI);
+ return result;
+}
+
+
+PARCURI *
+parcURI_CreateFromValist(const char *restrict format, va_list argList)
+{
+ PARCURI *result = NULL;
+
+ char *string;
+ if (vasprintf(&string, format, argList) != -1) {
+ result = parcURI_Parse(string);
+ free(string);
+ }
+ return result;
+}
+
+PARCURI *
+parcURI_CreateFromFormatString(const char *restrict format, ...)
+{
+ va_list argList;
+ va_start(argList, format);
+
+ PARCURI *result = parcURI_CreateFromValist(format, argList);
+
+ va_end(argList);
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcURI, PARCURI);
+
+parcObject_ImplementRelease(parcURI, PARCURI);
+
+static bool
+_parcURI_SchemeEquals(const char *schemeA, const char *schemeB)
+{
+ if (schemeA == schemeB) {
+ return true;
+ }
+ if (schemeA == NULL || schemeB == NULL) {
+ return false;
+ }
+ return strcmp(schemeA, schemeB) == 0;
+}
+
+static bool
+_parcURI_AuthorityEquals(const char *authorityA, const char *authorityB)
+{
+ if (authorityA == authorityB) {
+ return true;
+ }
+ if (authorityA == NULL || authorityB == NULL) {
+ return false;
+ }
+ return strcmp(authorityA, authorityB) == 0;
+}
+
+static bool
+_parcURI_QueryEquals(const char *queryA, const char *queryB)
+{
+ if (queryA == queryB) {
+ return true;
+ }
+ if (queryA == NULL || queryB == NULL) {
+ return false;
+ }
+ return strcmp(queryA, queryB) == 0;
+}
+
+static bool
+_parcURI_FragmentEquals(const char *fragmentA, const char *fragmentB)
+{
+ if (fragmentA == fragmentB) {
+ return true;
+ }
+ if (fragmentA == NULL || fragmentB == NULL) {
+ return false;
+ }
+ return strcmp(fragmentA, fragmentB) == 0;
+}
+
+bool
+parcURI_Equals(const PARCURI *uriA, const PARCURI *uriB)
+{
+ if (uriA == uriB) {
+ return true;
+ }
+ if (uriA == NULL || uriB == NULL) {
+ return false;
+ }
+
+ if (_parcURI_SchemeEquals(uriA->scheme, uriB->scheme)) {
+ if (_parcURI_AuthorityEquals(uriA->authority, uriB->authority)) {
+ if (parcURIPath_Equals(uriA->path, uriB->path)) {
+ if (_parcURI_QueryEquals(uriA->query, uriB->query)) {
+ if (_parcURI_FragmentEquals(uriA->fragment, uriB->fragment)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+/*
+ * Parse and return a copy of the scheme portion of the URI.
+ *
+ * If this function returns successfully,
+ * the input parameter @p pointer will point to either a null-byte or the first character
+ * after the ':' separating the scheme from the rest of the URI.
+ *
+ * @return non-NULL An allocated string copy of the string which must be freed by the caller via <code>parcMemory_Deallocate</code>.
+ * @return NULL The scheme is malformed.
+ */
+static char *
+_parseScheme(const char *uri, const char **pointer)
+{
+ size_t length = 0;
+
+ const char *p = uri;
+ while (*p != 0 && *p != ':') {
+ length++;
+ p++;
+ }
+ if (*p == 0) {
+ return NULL;
+ }
+
+ if (length == 0) {
+ return NULL;
+ }
+
+ char *result = parcMemory_StringDuplicate(uri, length);
+
+ *pointer = (char *) &uri[length + 1];
+ return result;
+}
+
+/**
+ * @function _parseAuthority
+ * @abstract Parse the authority portion of a URI, if present.
+ * @discussion
+ * A URI may have an optional authority component.
+ * If the given string begins with a double forward slash ("//"),
+ * then it is followed by an authority part and a path.
+ * If the string doesn't begin with ("//") it contains only a path and this
+ * function simply returns NULL and setting the give pointer to the first
+ * character of the (expected) path.
+ *
+ * @param string A pointer to the start of the (potential) authority component.
+ * @param pointer A pointer to a character pointer that will be assigned point to the first character that begins the path.
+ * @return An allocated string, to be freed via parcMemory_Deallocate, if the authority portion is present or NULL if otherwise.
+ */
+static char *
+_parseAuthority(const char *string, const char **pointer)
+{
+ if (string[0] == '/' && string[1] == '/') {
+ size_t length = 0;
+ for (const char *p = &string[2]; *p != '/'; p++) {
+ if (*p == 0) {
+ *pointer = p;
+ break;
+ }
+ length++;
+ }
+
+ char *result = parcMemory_StringDuplicate(&string[2], length);
+ // The pointer must point to the first character *after* the '/' character as the '/' is not part of the path.
+ *pointer = &(&string[2])[length];
+ return result;
+ }
+ *pointer = string;
+ return NULL;
+}
+
+static char *
+_parseQuery(const char *string, const char **pointer)
+{
+ if (*string != '?') {
+ return NULL;
+ }
+
+ string++;
+ size_t length = 0;
+ for (const char *p = string; *p != 0 && *p != '#'; p++) {
+ length++;
+ }
+
+ char *result = parcMemory_StringDuplicate(string, length);
+ *pointer = &string[length];
+ return result;
+}
+
+static char *
+_parseFragment(const char *string, const char **pointer)
+{
+ if (*string != '#') {
+ return NULL;
+ }
+ string++;
+ size_t length = 0;
+ for (const char *p = string; *p != 0; p++) {
+ length++;
+ }
+ char *result = parcMemory_StringDuplicate(string, length);
+
+ *pointer = &string[length];
+ return result;
+}
+
+static void
+_parcURI_SetScheme(PARCURI *uri, const char *scheme)
+{
+ if (uri->scheme != NULL) {
+ parcMemory_Deallocate((void **) &(uri->scheme));
+ }
+ if (scheme == NULL) {
+ uri->scheme = NULL;
+ } else {
+ uri->scheme = parcMemory_StringDuplicate(scheme, strlen(scheme));
+ }
+}
+
+static void
+_parcURI_SetAuthority(PARCURI *uri, const char *authority)
+{
+ if (uri->authority != NULL) {
+ parcMemory_Deallocate((void **) &(uri->authority));
+ }
+ if (authority == NULL) {
+ uri->authority = NULL;
+ } else {
+ uri->authority = parcMemory_StringDuplicate(authority, strlen(authority));
+ }
+}
+
+static void
+_parcURI_SetQuery(PARCURI *uri, const char *query)
+{
+ if (uri->query != NULL) {
+ parcMemory_Deallocate((void **) &(uri->query));
+ }
+ if (query == NULL) {
+ uri->query = NULL;
+ } else {
+ uri->query = parcMemory_StringDuplicate(query, strlen(query));
+ }
+}
+
+static void
+_parcURI_SetFragment(PARCURI *uri, const char *fragment)
+{
+ if (uri->fragment != NULL) {
+ parcMemory_Deallocate((void **) &(uri->fragment));
+ }
+ if (fragment == NULL) {
+ uri->fragment = NULL;
+ } else {
+ uri->fragment = parcMemory_StringDuplicate(fragment, strlen(fragment));
+ }
+}
+
+PARCURI *
+parcURI_Parse(const char *string)
+{
+ const char *pointer = string;
+
+ PARCURI *result = parcURI_Create();
+
+ if (result != NULL) {
+ result->scheme = _parseScheme(pointer, &pointer);
+ if (result->scheme != NULL) {
+ result->authority = _parseAuthority(pointer, &pointer);
+ result->path = parcURIPath_Parse(pointer, &pointer);
+ result->query = _parseQuery(pointer, &pointer);
+ result->fragment = _parseFragment(pointer, &pointer);
+ } else {
+ parcURI_Release(&result);
+ result = NULL;
+ }
+ }
+
+ return result;
+}
+
+PARCURI *
+parcURI_Copy(const PARCURI *uri)
+{
+ PARCURI *result = parcURI_Create();
+
+ if (result != NULL) {
+ _parcURI_SetScheme(result, parcURI_GetScheme(uri));
+ _parcURI_SetAuthority(result, parcURI_GetAuthority(uri));
+ result->path = parcURIPath_Copy(parcURI_GetPath(uri));
+ _parcURI_SetQuery(result, parcURI_GetQuery(uri));
+ _parcURI_SetFragment(result, parcURI_GetFragment(uri));
+ }
+
+ return result;
+}
+
+PARCBufferComposer *
+parcURI_BuildString(const PARCURI *uri, PARCBufferComposer *composer)
+{
+ parcBufferComposer_PutStrings(composer, parcURI_GetScheme(uri), ":", NULL);
+
+ if (parcURI_GetAuthority(uri)) {
+ parcBufferComposer_PutString(composer, "//");
+ parcBufferComposer_PutString(composer, parcURI_GetAuthority(uri));
+ }
+
+ parcBufferComposer_PutString(composer, "/");
+ parcURIPath_BuildString(parcURI_GetPath(uri), composer);
+
+ if (parcURI_GetQuery(uri)) {
+ parcBufferComposer_PutStrings(composer, "?", parcURI_GetQuery(uri), NULL);
+ }
+
+ if (parcURI_GetFragment(uri)) {
+ parcBufferComposer_PutStrings(composer, "#", parcURI_GetFragment(uri), NULL);
+ }
+
+ return composer;
+}
+
+char *
+parcURI_ToString(const PARCURI *uri)
+{
+ char *result = NULL;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ if (composer != NULL) {
+ if (parcURI_BuildString(uri, composer) != NULL) {
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ }
+ parcBufferComposer_Release(&composer);
+ }
+
+ return result;
+}
+
+const char *
+parcURI_GetScheme(const PARCURI *uri)
+{
+ return uri->scheme;
+}
+
+const char *
+parcURI_GetAuthority(const PARCURI *uri)
+{
+ return uri->authority;
+}
+
+PARCURIPath *
+parcURI_GetPath(const PARCURI *uri)
+{
+ return uri->path;
+}
+
+const char *
+parcURI_GetQuery(const PARCURI *uri)
+{
+ return uri->query;
+}
+
+const char *
+parcURI_GetFragment(const PARCURI *uri)
+{
+ return uri->fragment;
+}
diff --git a/libparc/parc/algol/parc_URI.h b/libparc/parc/algol/parc_URI.h
new file mode 100644
index 00000000..7ac6be1f
--- /dev/null
+++ b/libparc/parc/algol/parc_URI.h
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_URI.h
+ * @ingroup networking
+ * @brief A Universal Resource Identifier
+ *
+ * An RF2396 compliant URI implementation with facilities for composition, decomposition,
+ * comparison, manipulation, etc.
+ *
+ */
+#ifndef libparc_parc_URI_h
+#define libparc_parc_URI_h
+
+#include <parc/algol/parc_URIPath.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+struct parc_uri;
+typedef struct parc_uri PARCURI;
+
+/**
+ * Create a new `PARCURI` object.
+ *
+ * The new `PARCURI` object is empty.
+ *
+ * @return A pointer to a `PARCURI` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURI *uri = parcURI_Create();
+ * ...
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+PARCURI *parcURI_Create(void);
+
+/**
+ * Create a new instance of `PARCURI` from the given format string and arguments.
+ *
+ * @param [in] format A pointer to a nul-terminated printf format string
+ * @param [in] argList A pointer to a valid `va_list`
+ *
+ * @return non-NULL A pointer to a valid PARCURI instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * char *
+ * createFormatString(const char * restrict format, ...)
+ * {
+ * va_list argList;
+ * va_start(argList, format);
+ *
+ * PARCURI *uri = parcURI_CreateFromValist(format, argList);
+ *
+ * va_end(argList);
+ * return uri;
+ * }
+ * }
+ * @endcode
+ */
+PARCURI *parcURI_CreateFromValist(const char *restrict format, va_list argList);
+
+/**
+ * Create a new instance of `PARCURI` 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 PARCURI instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURI *uri = parcURI_CreateFromFormatString("http://%s/index.html", "127.0.0.1");
+ * }
+ * @endcode
+ */
+PARCURI *parcURI_CreateFromFormatString(const char *restrict format, ...);
+
+/**
+ * Increase the number of references to a `PARCURI` instance.
+ *
+ * Note that new `PARCURI` is not created,
+ * only that the given `PARCURI` reference count is incremented.
+ * Discard the reference by invoking {@link parcURI_Release}.
+ *
+ * @param uri A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURI *x = parcURI_Create();
+ *
+ * PARCURI *x2 = parcURI_Acquire(x);
+ *
+ * parcURI_Release(&x);
+ * parcURI_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see parcURI_Release
+ */
+PARCURI *parcURI_Acquire(const PARCURI *uri);
+
+/**
+ * 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] uriPtr A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURI *x = parcURI_Create();
+ *
+ * parcURI_Release(&x);
+ * }
+ * @endcode
+ */
+void parcURI_Release(PARCURI **uriPtr);
+
+/**
+ * Parse a well-formed URI into a `PARCURI` instance.
+ *
+ * The URI string must be null-terminated so that parsing can detect the
+ * end of the path correctly.
+ *
+ * @param [in] string The URI C-string used to create the `PARCURI` instance.
+ *
+ * @return non-NULL A pointer to an allocated `PARCURI` structure which must be destroyed via {@link parcURI_Release()}.
+ * @return NULL The URI was malformed.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://parc.com";
+ *
+ * PARCURI *uri = parcURI_Parse(uriString);
+ * if (uri == NULL) {
+ * printf("Malformed URI '%s', uriString);
+ * }
+ * }
+ * @endcode
+ */
+PARCURI *parcURI_Parse(const char *string);
+
+/**
+ * Create a deep copy of the given `PARCURI` instance.
+ *
+ * @param [in] uri A `PARCURI` pointer.
+ *
+ * @return A deep copy of the given `PARCURI` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://parc.com";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * PARCURI *copy = parcURI_Copy(uri);
+ * // uri and copy will contain equivalent paths
+ *
+ * parcURI_Release(&uri);
+ * parcURI_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCURI *parcURI_Copy(const PARCURI *uri);
+
+/**
+ * Return true if two `PARCURI` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCURI` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, equals(x, y) must return true if and only if
+ * equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * equals(x, y) returns true and
+ * equals(y, z) returns true,
+ * then equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, equals(x, NULL)) must return false.
+ *
+ * @param [in] uriA The first `PARCURI` instance.
+ * @param [in] uriB The second `PARCURI` instance.
+ *
+ * @return true the given `PARCURI` instances are equal.
+ * @return false the given `PARCURI` instances are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://parc.com";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ * PARCURI *copy = parcURI_Copy(uri);
+ *
+ * if (parcURI_Equals(uri, copy)) {
+ * printf("Paths are equal.\n");
+ * } else {
+ * printf("Paths are NOT equal.\n");
+ * }
+ *
+ * parcURI_Release(&uri);
+ * parcURI_Release(&copy);
+ * }
+ * @endcode
+ */
+bool parcURI_Equals(const PARCURI *uriA, const PARCURI *uriB);
+
+/**
+ * Get the scheme part of the given URI.
+ *
+ * The scheme of a URI path is the "type", e.g., labeled content
+ * identifier "lci" for "lci:/foo/bar".
+ *
+ * @param [in] uri A `PARCURI` pointer.
+ *
+ * @return char* The scheme of the given `PARCURI` instance
+ * @return NULL If no scheme is available.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://parc.com";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * const char *scheme = parcURI_GetScheme(uri); // will be "lci"
+ *
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+const char *parcURI_GetScheme(const PARCURI *uri);
+
+/**
+ * Get the authority part of the given `PARCURI`.
+ *
+ * The authority part of a URI is the string: username at host:port
+ *
+ * @param [in] uri A `PARCURI` pointer.
+ *
+ * @return char* The authority of the given `PARCURI` instance
+ * @return NULL If no scheme is available.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://chris@parc.com:80";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * const char *authority = parcURI_GetAuthority(uri); // will be "chris@parc.com:80"
+ *
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+const char *parcURI_GetAuthority(const PARCURI *uri);
+
+/**
+ * Get the {@link PARCURIPath} part of the given URI.
+ *
+ * Every `PARCURI` contains a `PARCURIPath` consisting of the path portion of the URI.
+ *
+ * @param [in] uri A `PARCURI` pointer.
+ *
+ * @return The `PARCURIPath` part of the given URI.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://parc.com/foo/bar/";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * const char *path = parcURI_GetPath(uri); // will be "/foo/bar/"
+ *
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURI_GetPath(const PARCURI *uri);
+
+/**
+ * Get the query part of the given PARCURI`.
+ *
+ * Queries are contiguous key-value string segments of a URI.
+ * For example, the query of URI string "http://parc.com/x=1&y=2&z=3" is "x=1&y=2&z=3"
+ *
+ * @param [in] uri A `PARCURI` pointer.
+ *
+ * @return char* The query string, if present, for the given URI
+ * @return NULL If no query string is present
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://parc.com/x=1&y=2&z=3";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * const char *path = parcURI_GetQuery(uri); // will be "x=1&y=2&z=3"
+ *
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+const char *parcURI_GetQuery(const PARCURI *uri);
+
+/**
+ * Get the fragment part of the given `PARCURI`.
+ *
+ * The fragment of a URI is the string component following the '#' character.
+ * For example, the fragment of URI string "http://parc.com/index.html#info" is "info"
+ *
+ * @param [in] uri A `PARCURI` pointer.
+ *
+ * @return char* The fragment of the URI, if present
+ * @return NULL If no fragment is in the URI
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://parc.com/index.html#info";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * const char *path = parcURI_GetFragment(uri); // will be "info"
+ *
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+const char *parcURI_GetFragment(const PARCURI *uri);
+
+/**
+ * Append a representation of the specified `PARCURI` instance to the given `PARCBufferComposer`.
+ *
+ * @param [in] uri A pointer to a `PARCURI` 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();
+ *
+ * parcURI_BuildString(instance, result);
+ *
+ * char *string = parcBufferComposer_ToString(result);
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate(string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcURI_BuildString(const PARCURI *uri, PARCBufferComposer *composer);
+
+/**
+ * Produce an allocated null-terminated string representation of the given URI.
+ *
+ * The returned value must be destroyed via `parcMemory_Deallocate`
+ *
+ * @param [in] uri The `PARCURI` instance to format.
+ *
+ * @return An allocated null-terminated string representation of the given URI.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://parc.com";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * printf("path string = %s\n", parcURI_ToString(uri));
+ *
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+char *parcURI_ToString(const PARCURI *uri);
+#endif // libparc_parc_URI_h
diff --git a/libparc/parc/algol/parc_URIAuthority.c b/libparc/parc/algol/parc_URIAuthority.c
new file mode 100644
index 00000000..ac2ee351
--- /dev/null
+++ b/libparc/parc/algol/parc_URIAuthority.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 <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#include <parc/algol/parc_URIAuthority.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+struct parc_uri_authority {
+ char *userinfo;
+ char *hostName;
+ long port;
+};
+
+static void
+_parcURIAuthority_Finalize(PARCURIAuthority **authorityPtr)
+{
+ PARCURIAuthority *authority = *authorityPtr;
+ parcMemory_SafeFree(authority->userinfo);
+ parcMemory_SafeFree(authority->hostName);
+}
+
+parcObject_ExtendPARCObject(PARCURIAuthority, _parcURIAuthority_Finalize, NULL, NULL, parcURIAuthority_Equals, NULL, NULL, NULL);
+
+PARCURIAuthority *
+parcURIAuthority_Create(void)
+{
+ PARCURIAuthority *result = parcObject_CreateInstance(PARCURIAuthority);
+ result->userinfo = 0;
+ result->hostName = 0;
+ result->port = 0;
+ return result;
+}
+
+parcObject_ImplementAcquire(parcURIAuthority, PARCURIAuthority);
+
+parcObject_ImplementRelease(parcURIAuthority, PARCURIAuthority);
+
+PARCURIAuthority *
+parcURIAuthority_Parse(const char *authority)
+{
+ PARCURIAuthority *result = parcURIAuthority_Create();
+
+ char *atSign = strchr(authority, '@');
+ if (atSign != NULL) {
+ result->userinfo = parcMemory_StringDuplicate(authority, atSign - authority);
+ authority = ++atSign;
+ }
+ // Support literal IPv6 address specifications (i.e. [::0]:80)
+ char *rightBracket = strrchr(authority, ']');
+ char *lastColon = strrchr(authority, ':');
+ if (rightBracket != NULL) {
+ result->hostName = parcMemory_StringDuplicate(authority, rightBracket - authority + 1);
+ if ((lastColon - rightBracket) > 0) {
+ result->port = (short) strtol(++lastColon, NULL, 10);
+ }
+ } else if (lastColon != NULL) {
+ result->hostName = parcMemory_StringDuplicate(authority, lastColon - authority);
+ result->port = (short) strtol(++lastColon, NULL, 10);
+ } else {
+ result->hostName = parcMemory_StringDuplicate(authority, strlen(authority));
+ }
+
+ return result;
+}
+
+const char *
+parcURIAuthority_GetUserInfo(const PARCURIAuthority *authority)
+{
+ return authority->userinfo;
+}
+
+const char *
+parcURIAuthority_GetHostName(const PARCURIAuthority *authority)
+{
+ return authority->hostName;
+}
+
+long
+parcURIAuthority_GetPort(const PARCURIAuthority *authority)
+{
+ return authority->port;
+}
+
+bool
+parcURIAuthority_Equals(const PARCURIAuthority *authA, const PARCURIAuthority *authB)
+{
+ if (authA == authB) {
+ return true;
+ }
+ if (authA == NULL || authB == NULL) {
+ return false;
+ }
+
+ if (strcmp(authA->hostName, authB->hostName) == 0) {
+ if (strcmp(authA->userinfo, authB->userinfo) == 0) {
+ if (authA->port == authB->port) {
+ return true;
+ }
+ return false;
+ }
+ return false;
+ }
+
+ return false;
+}
diff --git a/libparc/parc/algol/parc_URIAuthority.h b/libparc/parc/algol/parc_URIAuthority.h
new file mode 100644
index 00000000..49d19734
--- /dev/null
+++ b/libparc/parc/algol/parc_URIAuthority.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_URIAuthority.h
+ * @ingroup networking
+ * @brief A Universal Resource Identifier (URI) Authority
+ *
+ */
+#ifndef libparc_parc_URIAuthority_h
+#define libparc_parc_URIAuthority_h
+
+#include <stdbool.h>
+
+struct parc_uri_authority;
+typedef struct parc_uri_authority PARCURIAuthority;
+
+/**
+ * Create a new `PARCURIAuthority` object.
+ *
+ * The new `PARCURIAuthority` object is empty.
+ *
+ * @return A pointer to a `PARCURIAuthority` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURIAuthority *auth = parcURIAuthority_Create();
+ * ...
+ * parcURIAuthority_Release(&auth);
+ * }
+ * @endcode
+ */
+PARCURIAuthority *parcURIAuthority_Create(void);
+
+/**
+ * Increase the number of references to a `PARCURIAuthority` instance.
+ *
+ * Note that new `PARCURIAuthority` is not created,
+ * only that the given `PARCURIAuthority` reference count is incremented.
+ * Discard the reference by invoking `parcURIAuthority_Release`.
+ *
+ * @param auth A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURIAuthority *x = parcURIAuthority_Create();
+ *
+ * PARCURIAuthority *x2 = parcURIAuthority_Acquire(x);
+ *
+ * parcURIAuthority_Release(&x);
+ * parcURIAuthority_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see parcURIAuthority_Release
+ */
+PARCURIAuthority *parcURIAuthority_Acquire(const PARCURIAuthority *auth);
+
+/**
+ * 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] authPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURIAuthority *auth = parcURIAuthority_Create();
+ *
+ * parcURIAuthority_Release(&auth);
+ * }
+ * @endcode
+ */
+void parcURIAuthority_Release(PARCURIAuthority **authPtr);
+
+/**
+ * Return true if two `PARCURIAuthority` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCURIAuthority` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, parcURIAuthority_Equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, parcURIAuthority_Equals(x, y) must return true if and only if
+ * parcURIAuthority_Equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * parcURIAuthority_Equals(x, y) returns true and
+ * parcURIAuthority_Equals(y, z) returns true,
+ * then parcURIAuthority_Equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of parcURIAuthority_Equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, parcURIAuthority_Equals(x, NULL)) must return false.
+ *
+ * @param [in] authA The first `PARCURIAuthority` instance.
+ * @param [in] authB The second `PARCURIAuthority` instance.
+ *
+ * @return true the given `PARCURIAuthority` instances are equal.
+ * @return false the given `PARCURIAuthority` instances are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://chris@parc.com:80";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ * PARCURI_Authority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+ * PARCURI_Authority *handle = parcURIAuthority_Acquire(authority);
+ *
+ * if (parcURIAuthority_Equals(authority, handle)) {
+ * printf("Authorities are equal.\n");
+ * } else {
+ * printf("Authorities are NOT equal.\n");
+ * }
+ *
+ * parcURIAuthority_Release(&uri);
+ * parcURIAuthority_Release(&copy);
+ * }
+ * @endcode
+ */
+bool parcURIAuthority_Equals(const PARCURIAuthority *authA, const PARCURIAuthority *authB);
+
+/**
+ * Produce a `PARCURI_Authority` type from the authority string.
+ *
+ * The returned value must be destroyed via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] authority The authority string to parse.
+ *
+ * @return A newly allocated `PARCURI_Authority` string.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://chris@parc.com:80";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * PARCURI_Authority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+ * // use the authority
+ *
+ * parcURIAuthority_Release(&authority);
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+PARCURIAuthority *parcURIAuthority_Parse(const char *authority);
+
+/**
+ * Retrieve the user information from the given `PARCURI_Authority` instance.
+ *
+ * @param [in] authority The `PARCURI_Authority` instance being queried.
+ *
+ * @return The user info string component of the `PARCURI_Authority` instance. Copy the string prior to modification.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://chris@parc.com:80";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * PARCURI_Authority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+ * printf("User info: "%s\n", parcURIAuthority_GetUserInfo(authority));
+ *
+ * parcURIAuthority_Release(&authority);
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+const char *parcURIAuthority_GetUserInfo(const PARCURIAuthority *authority);
+
+/**
+ * Retrieve the host name from the given `PARCURI_Authority` instance.
+ *
+ * @param [in] authority The `PARCURI_Authority` instance being queried.
+ *
+ * @return The host name string component of the `PARCURI_Authority` instance. Copy the string prior to modification.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://chris@parc.com:80";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * PARCURI_Authority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+ * printf("Host name: "%s\n", parcURIAuthority_GetHostName(authority));
+ *
+ * parcURIAuthority_Release(&authority);
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+const char *parcURIAuthority_GetHostName(const PARCURIAuthority *authority);
+
+/**
+ * Retrieve the host port from the given `PARCURI_Authority` instance.
+ *
+ * @param [in] authority The `PARCURI_Authority` instance being queried.
+ *
+ * @return The host port string component of the `PARCURI_Authority` instance. Copy the string prior to modification.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *uriString = "http://chris@parc.com:80";
+ * PARCURI *uri = parcURI_Parse(uriString);
+ *
+ * PARCURI_Authority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+ * printf("Host port: "%s\n", parcURIAuthority_GetPort(authority));
+ *
+ * parcURIAuthority_Release(&authority);
+ * parcURI_Release(&uri);
+ * }
+ * @endcode
+ */
+long parcURIAuthority_GetPort(const PARCURIAuthority *authority);
+#endif /* defined(libparc_parc_URIAuthority_h) */
diff --git a/libparc/parc/algol/parc_URIPath.c b/libparc/parc/algol/parc_URIPath.c
new file mode 100755
index 00000000..ef46dac9
--- /dev/null
+++ b/libparc/parc/algol/parc_URIPath.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 <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#include <parc/algol/parc_URIPath.h>
+
+#include <parc/algol/parc_URISegment.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+struct parc_uri_path {
+ PARCArrayList *segments;
+};
+
+static void
+_parcURIPath_Finalize(PARCURIPath **pathPtr)
+{
+ assertNotNull(pathPtr, "Parameter must be a non-null pointer to a pointer to a PARCURIPath instance.");
+
+ PARCURIPath *path = *pathPtr;
+ if (path != NULL) {
+ parcArrayList_Destroy(&path->segments);
+ }
+}
+
+parcObject_ExtendPARCObject(PARCURIPath, _parcURIPath_Finalize, parcURIPath_Copy, parcURIPath_ToString, parcURIPath_Equals,
+ parcURIPath_Compare, NULL, NULL);
+
+PARCURIPath *
+parcURIPath_Create(void)
+{
+ PARCURIPath *result = parcObject_CreateInstance(PARCURIPath);
+ return result;
+}
+
+parcObject_ImplementAcquire(parcURIPath, PARCURIPath);
+
+parcObject_ImplementRelease(parcURIPath, PARCURIPath);
+
+PARCURIPath *
+parcURIPath_Append(PARCURIPath *path, const PARCURISegment *segment)
+{
+ parcArrayList_Add(path->segments, segment);
+ return path;
+}
+
+PARCURIPath *
+parcURIPath_Trim(PARCURIPath *path, size_t numberToRemove)
+{
+ size_t length = parcArrayList_Size(path->segments);
+ if (numberToRemove <= length) {
+ while (numberToRemove--) {
+ parcArrayList_RemoveAndDestroyAtIndex(path->segments, length - 1);
+ length--;
+ }
+ }
+ return path;
+}
+
+//PARCURIPath *
+//parcURIPath_Parse(const char *string, const char **pointer)
+//{
+// PARCURIPath *result = parcURIPath_Create();
+//
+// result->segments = parcArrayList_Create((void (*)(void **))parcURISegment_Release);
+// if (*string != 0) {
+// assertTrue(*string == '/', "Expected initial '/' character.");
+// *pointer = string;
+// while (**pointer != 0 && **pointer != '?' && **pointer != '#') {
+// PARCURISegment *segment = parcURISegment_Parse(++(*pointer), pointer);
+// parcURIPath_Append(result, segment);
+// }
+// }
+//
+// return result;
+//}
+
+PARCURIPath *
+parcURIPath_Parse(const char *string, const char **pointer)
+{
+ PARCURIPath *result = parcURIPath_Create();
+ result->segments = parcArrayList_Create((void (*)(void **))parcURISegment_Release);
+
+ if (*string != 0) {
+ if (*string != '/') {
+ parcURIPath_Release(&result);
+ return NULL;
+ }
+
+ *pointer = string;
+ while (**pointer != 0 && **pointer != '?' && **pointer != '#') {
+ PARCURISegment *segment = parcURISegment_Parse(++(*pointer), pointer);
+ parcURIPath_Append(result, segment);
+ }
+ }
+
+ return result;
+}
+
+bool
+parcURIPath_Equals(const PARCURIPath *pathA, const PARCURIPath *pathB)
+{
+ if (pathA == pathB) {
+ return true;
+ }
+ if (pathA == NULL || pathB == NULL) {
+ return false;
+ }
+
+ if (parcArrayList_Size(pathA->segments) == parcArrayList_Size(pathB->segments)) {
+ for (size_t i = 0; i < parcArrayList_Size(pathA->segments); i++) {
+ PARCURISegment *segmentA = parcArrayList_Get(pathA->segments, i);
+ PARCURISegment *segmentB = parcArrayList_Get(pathB->segments, i);
+ if (!parcURISegment_Equals(segmentA, segmentB)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+PARCURIPath *
+parcURIPath_Copy(const PARCURIPath *path)
+{
+ assertNotNull(path, "Parameter must be a non-null PARC_URIPath pointer.");
+
+ PARCURIPath *result = parcURIPath_Create();
+ result->segments = parcArrayList_Create((void (*)(void **))parcURISegment_Release);
+
+ size_t nSegments = parcURIPath_Count(path);
+
+ for (size_t i = 0; i < nSegments; i++) {
+ PARCURISegment *segment = parcURIPath_Get(path, i);
+ PARCURISegment *segmentCopy = parcURISegment_Clone(segment);
+ parcURIPath_Append(result, segmentCopy);
+ }
+
+ return result;
+}
+
+PARCURIPath *
+parcURIPath_ComposeValist(const PARCURIPath *basePath, va_list varargs)
+{
+ PARCURIPath *result = parcURIPath_Copy(basePath);
+
+ for (PARCURISegment *segment = va_arg(varargs, PARCURISegment *); segment != NULL; segment = va_arg(varargs, PARCURISegment *)) {
+ parcURIPath_Append(result, parcURISegment_Clone(segment));
+ }
+
+ return result;
+}
+
+PARCURIPath *
+parcURIPath_Compose(const PARCURIPath *basePath, ...)
+{
+ va_list arglist;
+ va_start(arglist, basePath);
+
+ PARCURIPath *result = parcURIPath_ComposeValist(basePath, arglist);
+ va_end(arglist);
+
+ return result;
+}
+
+bool
+parcURIPath_StartsWith(const PARCURIPath *base, const PARCURIPath *prefix)
+{
+ size_t prefixSegmentCount = parcURIPath_Count(prefix);
+ size_t baseSegmentCount = parcURIPath_Count(base);
+
+ if (baseSegmentCount < prefixSegmentCount) {
+ return false;
+ }
+
+ for (size_t i = 0; i < prefixSegmentCount; i++) {
+ PARCURISegment *baseSegment = parcURIPath_Get(base, i);
+ PARCURISegment *prefixSegment = parcURIPath_Get(prefix, i);
+ if (parcURISegment_Compare(baseSegment, prefixSegment) != 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+int
+parcURIPath_Compare(const PARCURIPath *pathA, const PARCURIPath *pathB)
+{
+ if (pathA == NULL) {
+ if (pathB == NULL) {
+ return 0;
+ }
+ return -1;
+ } else {
+ if (pathB == NULL) {
+ return +1;
+ }
+ }
+
+ ssize_t countDifference = parcURIPath_Count(pathA) - parcURIPath_Count(pathB);
+
+ if (countDifference != 0) {
+ return (countDifference > 0 ? 1 : (countDifference < 0) ? -1 : 0);
+ }
+
+ size_t nSegments = parcURIPath_Count(pathA);
+
+ for (size_t i = 0; i < nSegments; i++) {
+ PARCURISegment *segmentA = parcURIPath_Get(pathA, i);
+ PARCURISegment *segmentB = parcURIPath_Get(pathB, i);
+ int comparison = parcURISegment_Compare(segmentA, segmentB);
+ if (comparison != 0) {
+ return comparison;
+ }
+ }
+ return 0;
+}
+
+PARCURISegment *
+parcURIPath_Get(const PARCURIPath *path, size_t index)
+{
+ return (PARCURISegment *) parcArrayList_Get(path->segments, index);
+}
+
+size_t
+parcURIPath_Count(const PARCURIPath *path)
+{
+ size_t nSegments = parcArrayList_Size(path->segments);
+ return nSegments;
+}
+
+size_t
+parcURIPath_Length(const PARCURIPath *path)
+{
+ size_t result = 0;
+
+ size_t nSegments = parcURIPath_Count(path);
+
+ for (size_t i = 0; i < nSegments; i++) {
+ PARCURISegment *segment = parcURIPath_Get(path, i);
+ result += parcURISegment_Length(segment);
+ if (i < (nSegments - 1)) {
+ result++; // Include the size of the '/' separators.
+ }
+ }
+
+ return result;
+}
+
+PARCBufferComposer *
+parcURIPath_BuildString(const PARCURIPath *path, PARCBufferComposer *composer)
+{
+ size_t nSegments = parcArrayList_Size(path->segments);
+
+ for (size_t i = 0; i < nSegments && composer != NULL; i++) {
+ if (parcURISegment_BuildString(parcURIPath_Get(path, i), composer) == NULL) {
+ composer = NULL;
+ }
+ if (i < (nSegments - 1)) {
+ composer = parcBufferComposer_PutChar(composer, '/');
+ }
+ }
+
+ return composer;
+}
+
+char *
+parcURIPath_ToString(const PARCURIPath *path)
+{
+ char *result = NULL;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ if (composer != NULL) {
+ if (parcURIPath_BuildString(path, composer) != NULL) {
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ }
+ parcBufferComposer_Release(&composer);
+ }
+
+ return result;
+}
diff --git a/libparc/parc/algol/parc_URIPath.h b/libparc/parc/algol/parc_URIPath.h
new file mode 100755
index 00000000..d43d8651
--- /dev/null
+++ b/libparc/parc/algol/parc_URIPath.h
@@ -0,0 +1,494 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_URIPath.h
+ * @ingroup networking
+ * @brief A Universal Resource Identifier (URI) Path
+ *
+ */
+#ifndef libparc_PARCURIPath_h
+#define libparc_PARCURIPath_h
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <parc/algol/parc_URISegment.h>
+
+struct parc_uri_path;
+typedef struct parc_uri_path PARCURIPath;
+
+/**
+ * Create a new `PARCURIPath` object.
+ *
+ * The new `PARCURIPath` object is empty.
+ *
+ * @return A pointer to a `PARCURIPath` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURIPath *path = parcURIPath_Create();
+ * ...
+ * parcURIPath_Release(&path);
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURIPath_Create(void);
+
+/**
+ * Increase the number of references to a `PARCURIPath` instance.
+ *
+ * Note that new `PARCURIPath` is not created,
+ * only that the given `PARCURIPath` reference count is incremented.
+ * Discard the reference by invoking {@link parcURIPath_Release}.
+ *
+ * @param auth A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURIPath *x = parcURIPath_Create();
+ *
+ * PARCURIPath *x2 = parcURIPath_Acquire(x);
+ *
+ * parcURIPath_Release(&x);
+ * parcURIPath_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see parcURIPath_Release
+ */
+PARCURIPath *parcURIPath_Acquire(const PARCURIPath *auth);
+
+/**
+ * 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] pathPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURIPath *path = parcURIPath_Create();
+ *
+ * parcURIPath_Release(&auth);
+ * }
+ * @endcode
+ */
+void parcURIPath_Release(PARCURIPath **pathPtr);
+
+/**
+ * Parse a complete URI path composed of URI segments.
+ *
+ * The parsed path is expected to conform to the syntax of '/' segment ['/' segment]
+ * terminated by either a null, '?', or '#' character.
+ *
+ * @param [in] string A pointer to character array containing the first '/' of the path.
+ * @param [in] pointer A pointer to character pointer that will point to the first character that is not the path.
+ *
+ * @return A newly allocated `PARCURIPath` instance that must be freed via {@link parcURIPath_Release()}
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("lci:/foo/bar/, &pointer);
+ * // use the complete URI path
+ * parcURIPath_Release(&path);
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURIPath_Parse(const char *string, const char **pointer);
+
+/**
+ * Compares two `PARCURIPath` instances for order.
+ *
+ * As strings, URI paths are compared in normal lexographical order. This
+ * is analogous to strcmp(...).
+ *
+ * @param [in] pathA A `PARCURIPath` pointer, or NULL.
+ * @param [in] pathB A `PARCURIPath` pointer, or NULL.
+ *
+ * @return A negative integer, zero, or a positive integer as a is less than, equal to, or greater than b, accordingly.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *pathA = parcURIPath_Parse("lci:/foo/bar/, &pointer);
+ * PARCURIPath *pathB = parcURIPath_Parse("lci:/foo/bar/, &pointer);
+ * int cmp = parcURIPath_Compare(pathA, pathB);
+ * // cmp will be zero since both paths are the same
+ * }
+ * @endcode
+ */
+int parcURIPath_Compare(const PARCURIPath *pathA, const PARCURIPath *pathB);
+
+/**
+ * Create a new `PARCURIPath` comprised of a basePath concatenated with zero or more `PARCURISegment` instances.
+ *
+ * Create a new `PARCURIPath` instance comprised of the given `PARCURIPath`
+ * concatenated with the null terminated list of {@link PARCURISegment} instances.
+ *
+ * @param [in] basePath The base prefix path used to compose a new path
+ * @param [in] ... Any additional `PARCURISegment` instances that will be appended to the URI path.
+ *
+ * @return A newly allocated `PARCURIPath` instance
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *basePath = parcURIPath_Parse("lci:/foo/, &pointer);
+ * PARCURISegment *segment = parcURISegment_Create(3, "bar");
+ * PARCURIPath *path = parcURIPath_Compose(basePath, segment);
+ *
+ * // use the new composed path as needed
+ *
+ * parcURIPath_Release(&path);
+ * parcURIPath_Release(&basePath);
+ * parcURISegment_Destroy(&segment);
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURIPath_Compose(const PARCURIPath *basePath, ...);
+
+/**
+ * Create a new `PARCURIPath` comprised of a basePath concatenated with the number of given `PARCURISegment`
+ * instances provided by @p varargs.
+ *
+ * The variable number of `PARCURISegment` instances is signaled by the value `NULL` as the last element in @p varargs.
+ *
+ * @param [in] basePath The base prefix path used to compose a new path
+ * @param [in] varargs A valid va_list.
+ *
+ * @return A newly allocated `PARCURIPath` instance
+ *
+ * Example:
+ * @code
+ * PARCURIPath *
+ * myFunction(const PARCURIPath *basePath, ...)
+ * {
+ * va_list arglist;
+ * va_start(arglist, basePath);
+ *
+ * PARCURIPath *result = parcURIPath_ComposeValist(basePath, arglist);
+ * va_end(arglist);
+ *
+ * return result;
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURIPath_ComposeValist(const PARCURIPath *basePath, va_list varargs);
+
+/**
+ * Concatenate two paths together to form a single path.
+ *
+ * Concatenating "/a/b/" and "/c/d" URI paths will yield: "/a/b/c/d/".
+ *
+ * @param [in] pathA Pointer to the first path (prefix)
+ * @param [in] pathB Pointer to the second path (suffix)
+ *
+ * @return A `PARCURIPath` instance containing the concatenation of pathA and pathB, must be freed via {@link parcURIPath_Release()}
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *prefix = parcURIPath_Parse("lci:/foo/, &pointer);
+ * PARCURIPath *suffix = parcURIPath_Parse("/bar/", &pointer);
+ * PARCURIPath *concat = parcURIPath_Concat(prefix, suffix);
+ *
+ * // use the new path as needed
+ *
+ * parcURIPath_Release(&prefix);
+ * parcURIPath_Release(&suffix);
+ * parcURIPath_Release(&concat);
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURIPath_Concat(PARCURIPath *pathA, PARCURIPath *pathB);
+
+/**
+ * Determine if two `PARCURIPath` instances are equal.
+ *
+ * This function implements the following equivalence relations on non-null `PARCURIPath` instances:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcURIPath_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcURIPath_Equals(x, y)` must return true if and only if
+ * `parcURIPath_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcURIPath_Equals(x, y)` returns true and
+ * `parcURIPath_Equals(y, z)` returns true,
+ * then `parcURIPath_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcURIPath_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcURIPath_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] pathA First instance
+ * @param [in] pathB Second instance
+ *
+ * @return true Equal `PARCURIPath` instances
+ * @return false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *pathA = parcURIPath_Parse("lci:/foo/, &pointer);
+ * PARCURIPath *pathB = parcURIPath_Parse("lci:/foo/, &pointer);
+ *
+ * if (parcURIPath_Equals(pathA, pathB) {
+ * printf("Paths are equal\n");
+ * }
+ *
+ * parcURIPath_Release(&pathA);
+ * parcURIPath_Release(&pathB);
+ * }
+ * @endcode
+ */
+bool parcURIPath_Equals(const PARCURIPath *pathA, const PARCURIPath *pathB);
+
+/**
+ * Create a copy of the given `PARCURIPath`.
+ *
+ * This is a deep copy of the instance.
+ *
+ * @param [in] path The path to copy.
+ *
+ * @return A copy of the given `PARCURIPath`.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("lci:/foo/, &pointer);
+ * PARCURIPath *copy = parcURIPath_Copy(path);
+ *
+ * // use the copy as needed
+ *
+ * parcURIPath_Release(&path);
+ * parcURIPath_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURIPath_Copy(const PARCURIPath *path);
+
+/**
+ * Append a path segment to an existing URI path.
+ *
+ * Appending "bar" to "lci:/foo" will yield "lci:/foo/bar".
+ * This modifies the URI path instance in place - it does not allocate
+ * a new instance.
+ *
+ * @param [in,out] path The `PARCURIPath` instance to which the segment is appended
+ * @param [in] segment The {@link PARCURISegment} to append to the path
+ *
+ * @return The modified `PARCURIPath` instance (equal to the first parameter).
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("lci:/foo/, &pointer);
+ * PARCURISegment *segment = parcURISegment_Create(3, "bar");
+ * path = parcURIPath_Append(path, segment);
+ *
+ * // use the full path as necessary
+ *
+ * parcURIPath_Release(&path);
+ * parcURISegment_Destroy(&segment);
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURIPath_Append(PARCURIPath *path, const PARCURISegment *segment);
+
+/**
+ * Retrieve the URI path segment at the specified index.
+ *
+ * The index must be within the range [0, number of segments]
+ * prior to invocation. Otherwise, the program is terminated with LongBow trapOutOfBounds.
+ *
+ * @param [in] path A `PARCURIPath` instance to be examined.
+ * @param [in] index The index of the URI segment to retrieve.
+ *
+ * @return The {@link PARCURISegment} instance at the specified index.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("lci:/foo/, &pointer);
+ * PARCURISegment *segment = parcURIPath_Get(path, 0);
+ * // segment will be equal to "lci:"
+ *
+ * ...
+ *
+ * parcURIPath_Release(&path);
+ * parcURISegment_Destroy(&segment);
+ * }
+ * @endcode
+ */
+PARCURISegment *parcURIPath_Get(const PARCURIPath *path, size_t index);
+
+/**
+ * Return the number of segments in the given Path.
+ *
+ * @param [in] path The `PARCURIPath` instance to be examined.
+ *
+ * @return The integer length of the path, in segments.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("lci:/foo/, &pointer);
+ * size_t numSegments = parcURIPath_Count(path);
+ * ...
+ * parcURIPath_Release(&path);
+ * }
+ * @endcode
+ */
+size_t parcURIPath_Count(const PARCURIPath *path);
+
+/**
+ * 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] path A pointer to the instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A null-terminated string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("lci:/foo/, &pointer);
+ *
+ * char *stringRep = parcURIPath_ToString(path);
+ * printf("Path: %s\n", stringRep);
+ *
+ * parcURIPath_Release(&path);
+ * }
+ * @endcode
+ */
+char *parcURIPath_ToString(const PARCURIPath *path);
+
+/**
+ * Remove N trailing segments from the given Path.
+ *
+ * @param [in,out] path The `PARCURIPath` instance being modified.
+ * @param [in] numberToRemove The number of segments to remove from the end.
+ *
+ * @return `PARCURIPath` The given `PARCURIPath` that has been modified in place
+ * @return NULL If @p numberToRemove is too large.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("lci:/foo/, &pointer);
+ *
+ * ...
+ * path = parcURIPath_Trim(path, 1); // leaves "lci:/"
+ * ...
+ *
+ * parcURIPath_Release(&path);
+ * }
+ * @endcode
+ */
+PARCURIPath *parcURIPath_Trim(PARCURIPath *path, size_t numberToRemove);
+
+/**
+ * Build a string representation of the `PARCURIPath` stored in a {@link PARCBufferComposer} instance.
+ *
+ * @param [in] path The `PARCURIPath` instance from which the string representation is made.
+ * @param [in,out] composer The `PARCBufferComposer` which is modified in place with the string representation.
+ *
+ * @return `PARCBufferComposer` The modified `PARCBufferComposer` that was passed in.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("/foo/bar/, &pointer);
+ * PARCBufferComposer *composer = parcBufferComposer_Create();
+ *
+ * parcURIPath_BuildString(path, composer);
+ *
+ * PARCBuffer *string = parcBufferComposer_ProducerBuffer(composer);
+ * printf("URI: %s\n", parcBuffer_ToString(string));
+ * parcBuffer_Release(&string);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcURIPath_BuildString(const PARCURIPath *path, PARCBufferComposer *composer);
+
+/**
+ * Determine if a `PARCURIPath` begins with the specified URI prefix.
+ *
+ * @param [in] base The `PARCURIPath` instance which is being checked.
+ * @param [in] prefix The `PARCURIPath` prefix used to check as the prefix.
+ *
+ * @return true If the base is prefixed with the given `PARCURIPath`
+ * @return false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *whole = parcURIPath_Parse("lci:/foo/bar, &pointer);
+ * PARCURIPath *prefix = parcURIPath_Parse("lci:/foo/, &pointer);
+ *
+ * bool isPrefix(whole, prefix); // returns true
+ * }
+ * @endcode
+ */
+bool parcURIPath_StartsWith(const PARCURIPath *base, const PARCURIPath *prefix);
+
+/**
+ * Determine the length of the given `PARCURIPath` instance.
+ *
+ * @param [in] path The `PARCURIPath` instance which is being examined.
+ *
+ * @return The length of the `PARCURIPath`, in terms of the number of segments.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURIPath *path = parcURIPath_Parse("lci:/foo/, &pointer);
+ *
+ * size_t lengthOfPath = parcURIPath_Length(path); // returns 2
+ * }
+ * @endcode
+ */
+size_t parcURIPath_Length(const PARCURIPath *path);
+#endif // libparc_PARCURIPath_h
diff --git a/libparc/parc/algol/parc_URISegment.c b/libparc/parc/algol/parc_URISegment.c
new file mode 100755
index 00000000..7261c3aa
--- /dev/null
+++ b/libparc/parc/algol/parc_URISegment.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 <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#include <parc/algol/parc_URISegment.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+struct parc_uri_segment {
+ PARCBuffer *buffer;
+ bool requiresEscaping;
+};
+
+static char *hexDigitsUpper = "0123456789ABCDEF";
+static char *hexDigitsLower = "0123456789abcdef";
+
+// Given a value, return the low nibble as a hex character.
+static char
+_toHexDigit(const char value)
+{
+ return hexDigitsUpper[value & 0xF];
+}
+
+/**
+ * @function _fromHexDigit
+ * @abstract Given a hex character, return the decimal value.
+ * @discussion
+ * Given a simple character containing the ASCII value for a hexadecimal digit, return the actual value.
+ *
+ * @param hexDigit A hexadecimal digit as a character from the set of characters <code>0123456789ABCDEFabcdef</code>
+ * @return Return the decimal value of the given hex character. If not a hex character return a value > 15.
+ */
+static char
+_fromHexDigit(const char hexDigit)
+{
+ for (char i = 0; i < 16; i++) {
+ if (hexDigit == hexDigitsLower[(int) i] || hexDigit == hexDigitsUpper[(int) i]) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static const char *
+_parsePercentEncoded(const char *string, unsigned char *value)
+{
+ char c = *string++;
+ if (c != 0) {
+ unsigned char hi = _fromHexDigit(c);
+ if (hi > 15) {
+ return NULL;
+ }
+ c = *string++;
+ if (c != 0) {
+ unsigned char lo = _fromHexDigit(c);
+ if (lo > 15) {
+ return NULL;
+ }
+ *value = (unsigned char) (hi << 4 | lo);
+ return string;
+ }
+ }
+ return NULL;
+}
+
+#define uriPlainSegmentChar(c) (c != 0 && strchr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~", c) != NULL)
+
+static PARCBufferComposer *
+_parcURISegment_BuildString(const PARCURISegment *segment, PARCBufferComposer *composer)
+{
+ assertNotNull(composer, "Parameter must be a non-null pointer to a PARCBufferComposer.");
+
+ for (size_t i = 0; i < parcBuffer_Limit(segment->buffer) && composer != NULL; i++) {
+ unsigned char c = parcBuffer_GetAtIndex(segment->buffer, i);
+ if (uriPlainSegmentChar(c)) {
+ parcBufferComposer_PutChar(composer, c);
+ } else {
+ parcBufferComposer_PutChar(composer, '%');
+ parcBufferComposer_PutChar(composer, _toHexDigit(c >> 4));
+ parcBufferComposer_PutChar(composer, _toHexDigit(c));
+ }
+ }
+
+ return composer;
+}
+
+static void
+_parcURISegment_Finalize(PARCURISegment **segmentPtr)
+{
+ PARCURISegment *segment = *segmentPtr;
+
+ parcBuffer_Release(&(segment->buffer));
+}
+
+parcObject_ExtendPARCObject(PARCURISegment, _parcURISegment_Finalize, parcURISegment_Clone, parcURISegment_ToString,
+ parcURISegment_Equals, parcURISegment_Compare, NULL, NULL);
+
+PARCURISegment *
+parcURISegment_CreateFromBuffer(PARCBuffer *buffer)
+{
+ PARCURISegment *result = parcObject_CreateInstance(PARCURISegment);
+ if (result != NULL) {
+ result->buffer = parcBuffer_Acquire(buffer);
+ }
+ return result;
+}
+
+PARCURISegment *
+parcURISegment_Create(size_t length, const unsigned char segment[length])
+{
+ PARCURISegment *result = NULL;
+
+ PARCBuffer *buffer = parcBuffer_Allocate(length);
+ if (buffer != NULL) {
+ parcBuffer_PutArray(buffer, length, segment);
+ parcBuffer_Flip(buffer);
+ result = parcURISegment_CreateFromBuffer(buffer);
+ parcBuffer_Release(&buffer);
+ }
+ return result;
+}
+
+PARCURISegment *
+parcURISegment_Parse(const char *string, const char **pointer)
+{
+ assertFalse(*string == '/', "Input parameter '%s' must NOT point to an initial '/' character.", string);
+
+ unsigned char *segment = parcMemory_AllocateAndClear((strlen(string) + 1) * sizeof(unsigned char));
+ assertNotNull(segment, "parcMemory_AllocateAndClear(%zu) returned NULL", (strlen(string) + 1) * sizeof(unsigned char));
+ size_t length = 0;
+
+ unsigned char *r = segment;
+
+ const char *p = string;
+ while (*p && *p != '/' && *p != '?' && *p != '#') {
+ if (*p == '%') {
+ unsigned char value;
+ if ((p = _parsePercentEncoded(p + 1, &value)) == NULL) {
+ parcMemory_Deallocate((void **) &segment);
+ return NULL;
+ }
+ *r = value;
+ } else {
+ *r = *p++;
+ }
+ length++;
+ r++;
+ }
+ if (*p != 0) {
+ // absorb any extra slash characters.
+ while (p[1] == '/') {
+ p++;
+ }
+ }
+
+ PARCURISegment *result = parcURISegment_Create(length, segment);
+ parcMemory_Deallocate((void **) &segment);
+ if (pointer != NULL) {
+ *pointer = p;
+ }
+ return result;
+}
+
+parcObject_ImplementAcquire(parcURISegment, PARCURISegment);
+
+parcObject_ImplementRelease(parcURISegment, PARCURISegment);
+
+PARCBuffer *
+parcURISegment_GetBuffer(const PARCURISegment *segment)
+{
+ parcBuffer_Rewind(segment->buffer);
+ return segment->buffer;
+}
+
+size_t
+parcURISegment_Length(const PARCURISegment *segment)
+{
+ parcBuffer_Rewind(segment->buffer);
+ return parcBuffer_Remaining(segment->buffer);
+}
+
+bool
+parcURISegment_Equals(const PARCURISegment *segmentA, const PARCURISegment *segmentB)
+{
+ if (segmentA == segmentB) {
+ return true;
+ }
+ if (segmentA == NULL || segmentB == NULL) {
+ return false;
+ }
+ return parcBuffer_Equals(segmentA->buffer, segmentB->buffer);
+}
+
+PARCURISegment *
+parcURISegment_Clone(const PARCURISegment *segment)
+{
+ assertNotNull(segment, "Parameter must be a non-null PARC_URISegment pointer.");
+
+ PARCBuffer *copy = parcBuffer_Copy(segment->buffer);
+ PARCURISegment *result = parcURISegment_CreateFromBuffer(copy);
+ parcBuffer_Release(&copy);
+ return result;
+}
+
+int
+parcURISegment_Compare(const PARCURISegment *a, const PARCURISegment *b)
+{
+ if (a == NULL) {
+ if (b == NULL) {
+ return 0;
+ }
+ return -1;
+ } else {
+ if (b == NULL) {
+ return +1;
+ }
+ }
+
+ if (parcURISegment_Length(a) < parcURISegment_Length(b)) {
+ return -1;
+ }
+ if (parcURISegment_Length(a) > parcURISegment_Length(b)) {
+ return +1;
+ }
+ return parcBuffer_Compare(a->buffer, b->buffer);
+}
+
+PARCBufferComposer *
+parcURISegment_BuildString(const PARCURISegment *segment, PARCBufferComposer *composer)
+{
+ composer = _parcURISegment_BuildString(segment, composer);
+
+ return composer;
+}
+
+char *
+parcURISegment_ToString(const PARCURISegment *segment)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ char *result = NULL;
+
+ if (parcURISegment_BuildString(segment, composer)) {
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ }
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
diff --git a/libparc/parc/algol/parc_URISegment.h b/libparc/parc/algol/parc_URISegment.h
new file mode 100644
index 00000000..e7234d3f
--- /dev/null
+++ b/libparc/parc/algol/parc_URISegment.h
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_URISegment.h
+ * @ingroup networking
+ * @brief A Universal Resource Identifier (URI) Segment
+ *
+ */
+#ifndef libparc_parc_URISegment_h
+#define libparc_parc_URISegment_h
+
+#include <parc/algol/parc_BufferComposer.h>
+
+struct parc_uri_segment;
+typedef struct parc_uri_segment PARCURISegment;
+
+/**
+ * Create a `PARCURISegment` instance copying data from the given pointer and length.
+ *
+ * A `PARCURISegment` is a tuple consisting of a pointer to arbitrary memory containing the first byte
+ * of `length` bytes as the value of the segment.
+ *
+ * Since the input parameter `pointer` points to arbitrary memory,
+ * this function makes a private copy of the data.
+ *
+ * @param [in] length The length of the given array pointed to by @p segment.
+ * @param [in] segment A pointer to an array consisting of at least @p length bytes.
+ *
+ * @return A `PARCURISegment` instance referring to the given pointer and length.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *segment = parcURISegment_Create(5, "Hello");
+ * ...
+ * parcURISegment_Release(&segment);
+ * }
+ * @endcode
+ */
+PARCURISegment *parcURISegment_Create(size_t length, const unsigned char *segment);
+
+/**
+ * Create a `PARCURISegment` instance referencing the given {@link PARCBuffer}.
+ *
+ * A new reference to the given `PARCBuffer` is acquired.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` instance.
+ *
+ * @return A `PARCURISegment` instance referring to the given `PARCBuffer`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap("lci:/foo/bar", 12, 0, 12);
+ * PARCURISegment *segment = parcURISegment_CreateFromBuffer(buffer);
+ * ...
+ * parcURISegment_Release(&segment);
+ * }
+ * @endcode
+ */
+PARCURISegment *parcURISegment_CreateFromBuffer(PARCBuffer *buffer);
+
+/**
+ * Increase the number of references to a `PARCURISegment`.
+ *
+ * Note that new `PARCURISegment` is not created,
+ * only that the given `PARCURISegment` reference count is incremented.
+ * Discard the reference by invoking {@link parcURISegment_Release}.
+ *
+ * @param [in] segment A pointer to the original instance.
+ *
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *x = parcURISegment_Create(5, "Hello");
+ *
+ * PARCURISegment *x2 = parcURISegment_Acquire(x);
+ *
+ * parcURISegment_Release(&x);
+ * parcURISegment_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see {@link parcURISegment_Release}
+ */
+PARCURISegment *parcURISegment_Acquire(const PARCURISegment *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] segmentPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *x = parcURISegment_Create(5, "Hello");
+ *
+ * parcURISegment_Release(&x);
+ * }
+ * @endcode
+ */
+void parcURISegment_Release(PARCURISegment **segmentPtr);
+
+/**
+ * Compares two `PARCURISegment` instances for order.
+ *
+ * As strings, URI segments are compared in normal lexographical order. This
+ * is analogous to strcmp(...).
+ *
+ * @param [in] a A `PARCURISegment` pointer, or NULL.
+ * @param [in] b A `PARCURISegment` pointer, or NULL.
+ *
+ * @return A negative integer, zero, or a positive integer as a is less than, equal to, or greater than b, accordingly.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *segmentA = parcURISegment_Create(6, "HelloA");
+ * PARCURISegment *segmentB = parcURISegment_Create(6, "HelloB");
+ * int cmp = parcURISegment_Compare(segmentA, segmentB);
+ * // cmp will be a negative integer since "HelloA" < "HelloB"
+ * }
+ * @endcode
+ */
+int parcURISegment_Compare(const PARCURISegment *a, const PARCURISegment *b);
+
+/**
+ * Create an independant copy the given `PARCURISegment`
+ *
+ * A new URI segment is created as a complete copy of the original.
+ *
+ * @param [in] segment A pointer to a `PARCURISegment` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCURISegment` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *segment = parcURISegment_Create(5, "Hello");
+ * PARCURISegment *copy = parcURISegment_Clone(segment);
+ *
+ * // use either segment or copy as needed
+ *
+ * parcBuffer_Release(&copy);
+ * parcBuffer_Release(&segment);
+ * }
+ * @endcode
+ *
+ */
+PARCURISegment *parcURISegment_Clone(const PARCURISegment *segment);
+
+/**
+ * Determine if two `PARCURISegment` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCURISegment` instances are maintained
+ *
+ * * It is reflexive: for any non-null reference value x, `parcURISegment_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcURISegment_Equals(x, y)` must return true if and only if
+ * `parcURISegment_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcURISegment_Equals(x, y)` returns true and
+ * `parcURISegment_Equals(y, z)` returns true,
+ * then `parcURISegment_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcURISegment_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcURISegment_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] x A pointer to a `PARCURISegment` instance.
+ * @param [in] y A pointer to a `PARCURISegment` instance.
+ *
+ * @return true `PARCURISegment` x and y are equal.
+ * @return false `PARCURISegment` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *segmentA = parcURISegment_Create(5, "Hello");
+ * PARCURISegment *segmentB = parcURISegment_Create(5, "Hello");
+ *
+ * if (parcURISegment_Equals(segmentA, segmentB)) {
+ * printf("The URI segments are equal\n");
+ * } else {
+ * printf("The URI segments are NOT equal\n");
+ * }
+ *
+ * parcURISegment_Equals(&segmentA);
+ * parcURISegment_Equals(&segmentB);
+ * }
+ * @endcode
+ */
+bool parcURISegment_Equals(const PARCURISegment *x, const PARCURISegment *y);
+
+/**
+ * Parse a single URI segment.
+ *
+ * The input parameter string must point to a '/' which indicates the beginning of a segment.
+ * The segment is terminated by a null byte or a '?' or '#' character and may may be zero length.
+ * The output parameter pointer will be assigned the address of the first character that is not part of the parsed segment.
+ *
+ * The returned value must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] string Pointer to the beginning of the segment
+ * @param [in,out] pointer Will be assigned the address of the first character that is not part of the parsed segment.
+ *
+ * @return An allocated `PARCURISegment` the must be deallocated via `parcMemory_Deallocate`.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pointer;
+ * PARCURISegment *segment = parcURISegment_Parse("lci:/a/b/", &pointer);
+ * ...
+ * parcBuffer_Release(&segment);
+ * }
+ * @endcode
+ */
+PARCURISegment *parcURISegment_Parse(const char *string, const char **pointer);
+
+/**
+ * Get the {@link PARCBuffer} containing the content of the given URI segment.
+ *
+ * The PARCBuffer is always rewound (see {@link parcBuffer_Rewind}).
+ *
+ * @param [in] segment A `PARCURISegment` instance from which the buffer will be extracted.
+ *
+ * @return A `PARCBuffer` instance containing the URI segment bytes that must be freed via {@link parcBuffer_Release()}
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *segment = parcURISegment_Create(5, "Hello");
+ * PARCBuffer *segBuffer = parcURISegment_GetBuffer(segment);
+ * // use or display the segment buffer as needed...
+ *
+ * parcURISegment(&segment);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcURISegment_GetBuffer(const PARCURISegment *segment);
+
+/**
+ * Append a representation of the specified instance to the given {@link PARCBufferComposer}.
+ *
+ * The URI representation is escape-encoded for all characters specified
+ *
+ * @param [in] component A pointer to the instance to be appended to @p composer.
+ * @param [in,out] composer A `PARCBufferComposer` to which this URI segment is appended.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The given `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * parcURISegment_BuildString(instance, result);
+ *
+ * PARCBuffer *string = parcBufferComposer_FinalizeBuffer(result);
+ * printf("URI: %s\n", parcBuffer_ToString(string));
+ * parcBuffer_Release(&string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcURISegment_BuildString(const PARCURISegment *component, PARCBufferComposer *composer);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCURISegment` instance.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * The result is percent-encoding if necessary.
+ * A `PARCURISegment` may contain characters that are not permitted in the path in their native form.
+ * These characters must be 'percent encoded' using the '%' followed by the hexadecimal value of the character.
+ * For consistency, percent-encoded octets in the ranges of
+ * ALPHA (%41-%5A and %61-%7A),
+ * DIGIT (%30-%39),
+ * hyphen (%2D),
+ * period (%2E),
+ * underscore (%5F),
+ * or tilde (%7E)
+ * should not be created by URI producers and,
+ * when found in a URI,
+ * should be decoded to their corresponding unreserved characters by URI normalizers.
+ *
+ * @param [in] segment A pointer to the instance.
+ *
+ * @return An allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *instance = parcURISegment_Create(5, "Hello");
+ *
+ * char *string = parcURISegment_ToString(instance);
+ *
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ *
+ * parcURISegment_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see parcURISegment_Parse
+ */
+char *parcURISegment_ToString(const PARCURISegment *segment);
+
+/**
+ * Get the length, in bytes, of the given `PARCURISegment`.
+ *
+ * @param [in] segment A pointer to the segment to inspect.
+ *
+ * @return The length, in bytes, of the given `PARCURISegment`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCURISegment *instance = parcURISegment_Create(5, "Hello");
+ * size_t length = parcURISegment_Length(instance);
+ * // length will be 5
+ * }
+ * @endcode
+ */
+size_t parcURISegment_Length(const PARCURISegment *segment);
+#endif // libparc_parc_URISegment_h
diff --git a/libparc/parc/algol/parc_Unsigned.c b/libparc/parc/algol/parc_Unsigned.c
new file mode 100644
index 00000000..839f6b2b
--- /dev/null
+++ b/libparc/parc/algol/parc_Unsigned.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 <stdio.h>
+#include <config.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/algol/parc_Unsigned.h>
+
+struct PARCUnsigned {
+ unsigned x;
+};
+
+static bool
+_parcUnsigned_Destructor(PARCUnsigned **instancePtr)
+{
+ return true;
+}
+
+parcObject_ImplementAcquire(parcUnsigned, PARCUnsigned);
+
+parcObject_ImplementRelease(parcUnsigned, PARCUnsigned);
+
+parcObject_Override(PARCUnsigned, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcUnsigned_Destructor,
+ .copy = (PARCObjectCopy *) parcUnsigned_Copy,
+ .display = (PARCObjectDisplay *) parcUnsigned_Display,
+ .toString = (PARCObjectToString *) parcUnsigned_ToString,
+ .equals = (PARCObjectEquals *) parcUnsigned_Equals,
+ .compare = (PARCObjectCompare *) parcUnsigned_Compare,
+ .hashCode = (PARCObjectHashCode *) parcUnsigned_HashCode,
+ .toJSON = (PARCObjectToJSON *) parcUnsigned_ToJSON,
+ .display = (PARCObjectDisplay *) parcUnsigned_Display);
+
+void
+parcUnsigned_AssertValid(const PARCUnsigned *instance)
+{
+ assertTrue(parcUnsigned_IsValid(instance),
+ "PARCUnsigned is not valid.");
+}
+
+PARCUnsigned *
+parcUnsigned_Create(unsigned x)
+{
+ PARCUnsigned *result = parcObject_CreateInstance(PARCUnsigned);
+ if (result != NULL) {
+ result->x = x;
+ }
+ return result;
+}
+
+int
+parcUnsigned_Compare(const PARCUnsigned *val, const PARCUnsigned *other)
+{
+ int result = 0;
+
+ if (val == NULL) {
+ if (other != NULL) {
+ result = -1;
+ }
+ } else if (other == NULL) {
+ result = 1;
+ } else {
+ parcUnsigned_OptionalAssertValid(val);
+ parcUnsigned_OptionalAssertValid(other);
+
+ if (val->x < other->x) {
+ return -1;
+ } else if (val->x > other->x) {
+ return 1;
+ }
+ }
+
+ return result;
+}
+
+PARCUnsigned *
+parcUnsigned_Copy(const PARCUnsigned *original)
+{
+ PARCUnsigned *result = parcUnsigned_Create(original->x);
+
+ return result;
+}
+
+void
+parcUnsigned_Display(const PARCUnsigned *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCSUnsingned@%p {", instance);
+ parcDisplayIndented_PrintLine(indentation + 1, "%d", instance->x);
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcUnsigned_Equals(const PARCUnsigned *x, const PARCUnsigned *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ parcUnsigned_OptionalAssertValid(x);
+ parcUnsigned_OptionalAssertValid(y);
+
+ if (x->x == y->x) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcUnsigned_HashCode(const PARCUnsigned *x)
+{
+ PARCHashCode result = 0;
+
+ result = parcHashCode_Hash((uint8_t *) &(x->x), sizeof(x->x));
+
+ return result;
+}
+
+bool
+parcUnsigned_IsValid(const PARCUnsigned *x)
+{
+ bool result = false;
+
+ if (x != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcUnsigned_ToJSON(const PARCUnsigned *x)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ return result;
+}
+
+char *
+parcUnsigned_ToString(const PARCUnsigned *x)
+{
+ int length = snprintf(NULL, 0, "%d", x->x);
+ char*str = malloc(length + 1);
+ snprintf(str, length + 1, "%d", x->x);
+ return str;
+}
+
+unsigned
+parcUnsigned_GetUnsigned(const PARCUnsigned *x)
+{
+ parcUnsigned_OptionalAssertValid(x);
+
+ return x->x;
+}
diff --git a/libparc/parc/algol/parc_Unsigned.h b/libparc/parc/algol/parc_Unsigned.h
new file mode 100755
index 00000000..b61195e4
--- /dev/null
+++ b/libparc/parc/algol/parc_Unsigned.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 parc_Unsigned.h
+ * @ingroup types
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_Unsigned
+#define PARCLibrary_parc_Unsigned
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+typedef struct PARCUnsigned PARCUnsigned;
+extern parcObjectDescriptor_Declaration(PARCUnsigned);
+
+/**
+ */
+PARCUnsigned *parcUnsigned_Acquire(const PARCUnsigned *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcUnsigned_OptionalAssertValid(_instance_)
+#else
+# define parcUnsigned_OptionalAssertValid(_instance_) parcUnsigned_AssertValid(_instance_)
+#endif
+
+/**
+ */
+void parcUnsinged_AssertValid(const PARCUnsigned *instance);
+
+/**
+ */
+PARCUnsigned *parcUnsigned_Create(unsigned x);
+
+
+/**
+ */
+int parcUnsigned_Compare(const PARCUnsigned *instance, const PARCUnsigned *other);
+
+/**
+ */
+PARCUnsigned *parcUnsigned_Copy(const PARCUnsigned *original);
+
+/**
+ */
+void parcUnsigned_Display(const PARCUnsigned *instance, int indentation);
+
+/**
+ */
+bool parcUnsigned_Equals(const PARCUnsigned *x, const PARCUnsigned *y);
+
+/**
+ */
+PARCHashCode parcUnsigned_HashCode(const PARCUnsigned *instance);
+
+/**
+ */
+bool parcUnsigned_IsValid(const PARCUnsigned *instance);
+
+/**
+ */
+void parcUnsigned_Release(PARCUnsigned **instancePtr);
+
+/**
+ */
+PARCJSON *parcUnsigned_ToJSON(const PARCUnsigned *instance);
+
+/**
+ */
+char *parcUnsigned_ToString(const PARCUnsigned *instance);
+
+/**
+ */
+unsigned parcUnsigned_GetUnsigned(const PARCUnsigned *istance);
+#endif
diff --git a/libparc/parc/algol/parc_Varint.c b/libparc/parc/algol/parc_Varint.c
new file mode 100755
index 00000000..7a593f45
--- /dev/null
+++ b/libparc/parc/algol/parc_Varint.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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <parc/algol/parc_Varint.h>
+#include <parc/algol/parc_Memory.h>
+
+struct parc_varint {
+ uint64_t value;
+};
+
+PARCVarint *
+parcVarint_Create(void)
+{
+ PARCVarint *result = parcMemory_AllocateAndClear(sizeof(PARCVarint));
+ if (result != NULL) {
+ result->value = 0;
+ }
+ return result;
+}
+
+PARCVarint *
+parcVarint_DecodeBuffer(PARCBuffer *buffer, size_t length)
+{
+ assertNotNull(buffer, "Parameter must be a non-null PARCBuffer pointer.");
+ assertTrue(length < sizeof(size_t), "Length must be less then or equal to %zd", sizeof(size_t));
+ assertTrue(length <= parcBuffer_Remaining(buffer), "Buffer does not contain at least %zd bytes", length);
+
+ PARCVarint *result = parcVarint_Create();
+ assertNotNull(result, "PARCVarint out of memory.");
+
+ for (size_t i = 0; i < length; i++) {
+ parcVarint_ShiftLeft(result, 8);
+ parcVarint_OrUint8(result, parcBuffer_GetUint8(buffer));
+ }
+
+ return result;
+}
+
+PARCVarint *
+parcVarint_DecodeElasticByteBuffer(const PARCBuffer *buffer, size_t length)
+{
+ assertNotNull(buffer, "Parameter must be a non-null PARCBuffer pointer.");
+ assertTrue(length < sizeof(size_t), "Length must be less then or equal to %zd", sizeof(size_t));
+
+ PARCVarint *result = parcVarint_Create();
+ assertNotNull(result, "PARCVarint out of memory.");
+
+ for (size_t i = 0; i < length; i++) {
+ parcVarint_ShiftLeft(result, 8);
+ parcVarint_OrUint8(result, parcBuffer_GetAtIndex(buffer, i));
+ }
+
+ return result;
+}
+
+PARCVarint *
+parcVarint_Set(PARCVarint *varint, uint64_t newValue)
+{
+ varint->value = newValue;
+ return varint;
+}
+
+PARCVarint *
+parcVarint_FromElasticByteBuffer(const PARCBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter must be a non-null PARCBuffer pointer.");
+ PARCVarint *result = parcVarint_Create();
+
+ size_t length = parcBuffer_Remaining(buffer);
+
+ for (size_t i = 0; i < length; i++) {
+ parcVarint_ShiftLeft(result, 8);
+ parcVarint_OrUint8(result, parcBuffer_GetAtIndex(buffer, i));
+ }
+
+ return result;
+}
+
+PARCVarint *
+parcVarint_FromUTF8ByteBuffer(const PARCBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter must not be NULL.");
+ PARCVarint *result = parcVarint_Create();
+
+ if (result != NULL) {
+ size_t length = parcBuffer_Remaining(buffer);
+
+ for (size_t i = 0; i < length; i++) {
+ parcVarint_Multiply(result, 10);
+ parcVarint_Add(result, parcBuffer_GetAtIndex(buffer, i) - '0');
+ }
+ }
+
+ return result;
+}
+
+PARCVarint *
+parcVarint_FromUTF8Buffer(PARCBuffer *buffer)
+{
+ assertNotNull(buffer, "Parameter must be a non-null PARCBuffer pointer.");
+ PARCVarint *result = parcVarint_Create();
+
+ if (result != NULL) {
+ size_t length = parcBuffer_Limit(buffer);
+
+ for (size_t i = 0; i < length; i++) {
+ parcVarint_Multiply(result, 10);
+ parcVarint_Add(result, parcBuffer_GetAtIndex(buffer, i) - '0');
+ }
+ }
+
+ return result;
+}
+
+/**
+ *
+ * @param uint
+ * @return
+ */
+PARCVarint *
+parcVarint_FromUint8(uint8_t uint)
+{
+ return parcVarint_FromUint32(uint);
+}
+
+/**
+ *
+ * @param uint
+ * @return
+ */
+PARCVarint *
+parcVarint_FromUint32(uint32_t uint)
+{
+ return parcVarint_FromUint64(uint);
+}
+
+/**
+ *
+ * @param uint
+ * @return
+ */
+PARCVarint *
+parcVarint_FromUint64(uint64_t uint)
+{
+ PARCVarint *result = parcMemory_AllocateAndClear(sizeof(PARCVarint));
+ if (result != NULL) {
+ result->value = uint;
+ }
+ return result;
+}
+
+/**
+ *
+ * @param varintP
+ */
+void
+parcVarint_Destroy(PARCVarint **varintP)
+{
+ assertNotNull(varintP, "Parameter must be a non-null pointer to a pointer to a PARCVarint");
+ assertNotNull(*varintP, "Parameter must be a non-null pointer to a PARCVarint");
+
+ parcMemory_Deallocate((void **) varintP);
+ *varintP = NULL;
+}
+
+/**
+ * Shift the value {@code bits} to the left.
+ *
+ * @param varint
+ * @param bits
+ * @return
+ */
+PARCVarint *
+parcVarint_ShiftLeft(PARCVarint *varint, int bits)
+{
+ assertNotNull(varint, "Parameter must be a non-null pointer to a PARCVarint.");
+ varint->value <<= bits;
+
+ return varint;
+}
+
+PARCVarint *
+parcVarint_Add(PARCVarint *varint, int addend)
+{
+ assertNotNull(varint, "Parameter must be a non-null pointer to a PARCVarint.");
+ varint->value += addend;
+
+ return varint;
+}
+
+PARCVarint *
+parcVarint_Subtract(PARCVarint *varint, int subtrahend)
+{
+ assertNotNull(varint, "Parameter must be a non-null pointer to a PARCVarint.");
+ varint->value -= subtrahend;
+
+ return varint;
+}
+
+PARCVarint *
+parcVarint_Multiply(PARCVarint *varint, int multiplicand)
+{
+ assertNotNull(varint, "Parameter must be a non-null pointer to a PARCVarint.");
+ varint->value *= multiplicand;
+
+ return varint;
+}
+
+PARCVarint *
+parcVarint_Divide(PARCVarint *varint, int divisor)
+{
+ assertNotNull(varint, "Parameter must be a non-null pointer to a PARCVarint.");
+ varint->value /= divisor;
+
+ return varint;
+}
+
+/**
+ * Shift the value {@code bits} to the right.
+ *
+ * @param varint
+ * @param bits
+ * @return
+ */
+PARCVarint *
+parcVarint_ShiftRight(PARCVarint *varint, int bits)
+{
+ assertNotNull(varint, "Parameter must be a non-null pointer to a PARCVarint.");
+ varint->value >>= bits;
+ return varint;
+}
+
+/**
+ * Perform an AND operation on the given {@link PARCVarint} with the supplied {@code operand},
+ * leaving the result in {@code varint}.
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_And(PARCVarint *varint, PARCVarint *operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ assertNotNull(operand, "Parameter operand must not be NULL.");
+ varint->value &= operand->value;
+ return varint;
+}
+
+/**
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_AndUint8(PARCVarint *varint, uint8_t operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ varint->value &= operand;
+ return varint;
+}
+
+/**
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_AndUint16(PARCVarint *varint, uint16_t operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ varint->value &= operand;
+ return varint;
+}
+
+/**
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_AndUint32(PARCVarint *varint, uint32_t operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ varint->value &= operand;
+ return varint;
+}
+
+/**
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_AndUint64(PARCVarint *varint, uint64_t operand)
+{
+ assertNotNull(varint, "Parameter must be a non-null PARCVarint pointer.");
+ varint->value &= operand;
+ return varint;
+}
+
+/**
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_Or(PARCVarint *varint, PARCVarint *operand)
+{
+ assertNotNull(varint, "Parameter must be a non-null PARCVarint pointer.");
+ varint->value |= operand->value;
+ return varint;
+}
+
+/**
+ * Perform an OR operation on the low 8-bits in the given {@link PARCVarint}.
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_OrUint8(PARCVarint *varint, uint8_t operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ varint->value |= operand;
+ return varint;
+}
+
+/**
+ * Perform an OR operation on the low 16-bits in the given {@link PARCVarint}.
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_OrUint16(PARCVarint *varint, uint16_t operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ varint->value |= operand;
+ return varint;
+}
+
+/**
+ * Perform an OR operation on the low 32-bits in the given {@link PARCVarint}.
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_OrUint32(PARCVarint *varint, uint32_t operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ varint->value |= operand;
+ return varint;
+}
+
+/**
+ * Perform an OR operation on the low 64-bits in the given {@link PARCVarint}.
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+PARCVarint *
+parcVarint_OrUint64(PARCVarint *varint, uint64_t operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ varint->value |= operand;
+ return varint;
+}
+
+/**
+ * Return {@code true} (non-zero) if the two {@link PARCVarint} structures contain equal data.
+ *
+ * @param varint
+ * @param operand
+ * @return
+ */
+int
+parcVarint_Equals(PARCVarint *varint, PARCVarint *operand)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return varint->value == operand->value;
+}
+
+/**
+ *
+ * @param varint
+ * @param value
+ * @return
+ */
+int
+parcVarint_EqualsUint64(PARCVarint *varint, uint64_t value)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return varint->value == value;
+}
+
+/**
+ *
+ * @param varint
+ * @param value
+ * @return
+ */
+int
+parcVarint_EqualsUint32(PARCVarint *varint, uint32_t value)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return parcVarint_EqualsUint64(varint, (uint64_t) value);
+}
+
+/**
+ *
+ * @param varint
+ * @param value
+ * @return
+ */
+int
+parcVarint_EqualsUint16(PARCVarint *varint, uint16_t value)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return parcVarint_EqualsUint64(varint, (uint64_t) value);
+}
+
+/**
+ *
+ * @param varint
+ * @param value
+ * @return
+ */
+int
+parcVarint_EqualsUint8(PARCVarint *varint, uint8_t value)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return parcVarint_EqualsUint64(varint, (uint64_t) value);
+}
+
+/**
+ * Produce the 8 low-order bits of this {@code PARCVarint}.
+ *
+ * @param varint
+ * @return
+ */
+uint8_t
+parcVarint_AsUint8(const PARCVarint *varint)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return (uint8_t) varint->value;
+}
+
+/**
+ * Produce the 16 low-order bits of this {@code PARCVarint}.
+ *
+ * @param varint
+ * @return
+ */
+uint16_t
+parcVarint_AsUint16(const PARCVarint *varint)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return (uint16_t) varint->value;
+}
+
+/**
+ * Produce the 32 low-order bits of this {@code PARCVarint}.
+ *
+ * @param varint
+ * @return
+ */
+uint32_t
+parcVarint_AsUint32(const PARCVarint *varint)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return (uint32_t) varint->value;
+}
+
+uint64_t
+parcVarint_AsUint64(const PARCVarint *varint)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return varint->value;
+}
+
+/**
+ * Produce the value of this {@code PARCVarint} as a {@code size_t} value.
+ *
+ * @param varint
+ * @return
+ */
+size_t
+parcVarint_AsSize(const PARCVarint *varint)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ return (size_t) varint->value;
+}
+
+/**
+ * Produce a string representation of this {@link PARCVarint}.
+ * The returned value must be freed by the called using the {@code stdlib.h} {@code free}.
+ * @param string
+ * @param varint
+ * @return
+ */
+char *
+parcVarint_ToString(char **string, PARCVarint *varint)
+{
+ assertNotNull(varint, "Parameter varint must not be NULL.");
+ int nwritten = asprintf(string, "%" PRIu64, varint->value);
+ assertTrue(nwritten >= 0, "Error calling asprintf");
+ return *string;
+}
diff --git a/libparc/parc/algol/parc_Varint.h b/libparc/parc/algol/parc_Varint.h
new file mode 100755
index 00000000..6d7e60b8
--- /dev/null
+++ b/libparc/parc/algol/parc_Varint.h
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Varint.h
+ * @ingroup datastructures
+ * @brief A Variable Length Integer.
+ *
+ * A variable length integer.
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#ifndef libparc_parc_VarInt_h
+#define libparc_parc_VarInt_h
+
+#include <stdint.h>
+
+#include <parc/algol/parc_Buffer.h>
+
+/**
+ * A variable length integer value.
+ * <em>
+ * This particular implementation is limited to a 64 bit value.
+ * </em>
+ */
+struct parc_varint;
+typedef struct parc_varint PARCVarint;
+
+
+#define PARC_VARINT_INIT { 0 }
+
+/**
+ * Create a new instance of `PARCVarint`
+ *
+ * @return A `PARCVarint` pointer, which must be deallocated via {@link parcVarint_Destroy()}.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVarint *parcVarint_Create(void);
+
+/**
+ * Decode an instance of {@link PARCBuffer} of length @p length into a new instance of `PARCVarInt`
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer`.
+ * @param [in] length The number of bytes to decode.
+ * @return A `PARCVarint` pointer, which must be deallocated via {@link parcVarint_Destroy()}.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode */
+PARCVarint *parcVarint_DecodeBuffer(PARCBuffer *buffer, size_t length);
+
+/**
+ * Decode an instance of {@link PARCBuffer} of length @p length into a new instance of `PARCVarInt`
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer`.
+ * @param [in] length The number of bytes to decode.
+ * @return A `PARCVarint` pointer, which must be deallocated via {@link parcVarint_Destroy()}.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVarint *parcVarint_DecodeElasticByteBuffer(const PARCBuffer *buffer, size_t length);
+
+/**
+ * Create a new `PARCVarint` from bytes in a {@link PARCBuffer}.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer`.
+ * @return A `PARCVarint` pointer, which must be deallocated via {@link parcVarint_Destroy()}.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVarint *parcVarint_FromElasticByteBuffer(const PARCBuffer *buffer);
+
+/**
+ * Create a `PARCVarint` with the value decoded from the given {@link PARCBuffer}
+ * containing a UTF-8 string encoded number.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` containing a UTF-8 string encoded number.
+ * @return A `PARCVarint` pointer, which must be deallocated via {@link parcVarint_Destroy()}.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVarint *parcVarint_FromUTF8Buffer(PARCBuffer *buffer);
+
+/**
+ * Create a `PARCVarint` with the value decoded from the given {@link PARCBuffer}
+ * containing a UTF-8 string encoded number.
+ *
+ * @param [in] buffer A pointer to a `PARCBuffer` containing a UTF-8 string encoded number.
+ * @return A `PARCVarint` pointer, which must be deallocated via {@link parcVarint_Destroy()}.
+ *
+ */
+PARCVarint *parcVarint_FromUTF8ByteBuffer(const PARCBuffer *buffer);
+
+
+extern PARCVarint *parcVarint_FromUint8(uint8_t uint);
+
+extern PARCVarint *parcVarint_FromUint32(uint32_t uint);
+
+extern PARCVarint *parcVarint_FromUint64(uint64_t uint);
+
+extern PARCVarint *parcVarint_ShiftLeft(PARCVarint *varint, int bits);
+
+extern PARCVarint *parcVarint_ShiftRight(PARCVarint *varint, int bits);
+
+extern PARCVarint *parcVarint_And(PARCVarint *varint, PARCVarint *operand);
+
+extern PARCVarint *parcVarint_AndUint8(PARCVarint *varint, uint8_t operand);
+
+extern PARCVarint *parcVarint_AndUint16(PARCVarint *varint, uint16_t operand);
+
+extern PARCVarint *parcVarint_AndUint32(PARCVarint *varint, uint32_t operand);
+
+extern PARCVarint *parcVarint_AndUint64(PARCVarint *varint, uint64_t operand);
+
+extern PARCVarint *parcVarint_Or(PARCVarint *varint, PARCVarint *operand);
+
+extern PARCVarint *parcVarint_OrUint8(PARCVarint *varint, uint8_t operand);
+
+extern PARCVarint *parcVarint_OrUint16(PARCVarint *varint, uint16_t operand);
+
+extern PARCVarint *parcVarint_OrUint32(PARCVarint *varint, uint32_t operand);
+
+extern PARCVarint *parcVarint_OrUint64(PARCVarint *varint, uint64_t operand);
+
+/**
+ * Determine if two `PARCVarint` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCVarint` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCVarint_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcVarint_Equals(x, y)` must return true if and only if
+ * `parcVarint_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcVarint_Equals(x, y)` returns true and
+ * `parcVarint_Equals(y, z)` returns true,
+ * then `parcVarint_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcVarint_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcVarint_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param varint A pointer to a `PARCVarint` instance.
+ * @param operand A pointer to a `PARCVarint` instance.
+ * @return true if the two `PARCVarint` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVarint *a = parcVarint_Create();
+ * PARCVarint *b = parcVarint_Create();
+ *
+ * if (parcVarint_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+
+extern int parcVarint_Equals(PARCVarint *varint, PARCVarint *operand);
+
+/**
+ * Determine if a `PARCVarint` instance is equal to a 64bit integer.
+ *
+ * The following equivalence relations on non-null `PARCVarint` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCVarint_Uint64Equals(x, x)`
+ * must return true.
+ *
+ * * It is NOT symmetric: for any non-null reference values x and y,
+ * `parcVarint_Uint64Equals(x, y)` may not return true even if
+ * `parcVarint_Uint64Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcVarint_Uint64Equals(x, y)` returns true and
+ * `parcVarint_Uint64Equals(y, z)` returns true,
+ * then `parcVarint_Uint64Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcVarint_Uint64Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcVarint_Uint64Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] varint A pointer to a `PARCVarint` instance.
+ * @param [in] value A pointer to a `uint64_t` instance.
+ * @return true if the two instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVarint *a = parcVarint_Create();
+ * uint64_t *b = 10; // some integer value
+ *
+ * if (parcVarint_Uint64Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+extern int parcVarint_EqualsUint64(PARCVarint *varint, uint64_t value);
+
+/**
+ * Determine if a `PARCVarint` instance is equal to a 32 bit integer.
+ *
+ * The following equivalence relations on non-null `PARCVarint` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCVarint_Uint32Equals(x, x)`
+ * must return true.
+ *
+ * * It is NOT symmetric: for any non-null reference values x and y,
+ * `parcVarint_Uint32Equals(x, y)` may not return true even if
+ * `parcVarint_Uint32Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcVarint_Uint32Equals(x, y)` returns true and
+ * `parcVarint_Uint32Equals(y, z)` returns true,
+ * then `parcVarint_Uint32Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcVarint_Uint32Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcVarint_Uint32Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] varint A pointer to a `PARCVarint` instance.
+ * @param [in] value A pointer to a `uint32_t` instance.
+ * @return true if the two instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVarint *a = parcVarint_Create();
+ * uint32_t *b = 10; // some integer value
+ *
+ * if (parcVarint_Uint32Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+extern int parcVarint_EqualsUint32(PARCVarint *varint, uint32_t value);
+
+/**
+ * Determine if a `PARCVarint` instance is equal to a 16 bit integer.
+ *
+ * The following equivalence relations on non-null `PARCVarint` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCVarint_Uint16Equals(x, x)`
+ * must return true.
+ *
+ * * It is NOT symmetric: for any non-null reference values x and y,
+ * `parcVarint_Uint16Equals(x, y)` may not return true even if
+ * `parcVarint_Uint16Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcVarint_Uint16Equals(x, y)` returns true and
+ * `parcVarint_Uint16Equals(y, z)` returns true,
+ * then `parcVarint_Uint16Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcVarint_Uint16Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcVarint_Uint16Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] varint A pointer to a `PARCVarint` instance.
+ * @param [in] value A pointer to a `uint16_t` instance.
+ * @return true if the two instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVarint *a = parcVarint_Create();
+ * uint16_t *b = 10; // some integer value
+ *
+ * if (parcVarint_Uint16Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+extern int parcVarint_EqualsUint16(PARCVarint *varint, uint16_t value);
+
+/**
+ * Determine if a `PARCVarint` instance is equal to an 8 bit integer.
+ *
+ * The following equivalence relations on non-null `PARCVarint` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `PARCVarint_Uint8Equals(x, x)`
+ * must return true.
+ *
+ * * It is NOT symmetric: for any non-null reference values x and y,
+ * `parcVarint_Uint8Equals(x, y)` may not return true even if
+ * `parcVarint_Uint8Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcVarint_Uint8Equals(x, y)` returns true and
+ * `parcVarint_Uint8Equals(y, z)` returns true,
+ * then `parcVarint_Uint8Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcVarint_Uint8Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcVarint_Uint8Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] varint A pointer to a `PARCVarint` instance.
+ * @param [in] value A pointer to a `uint8_t` instance.
+ * @return true if the two instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVarint *a = parcVarint_Create();
+ * uint8_t *b = 10; // some integer value
+ *
+ * if (parcVarint_Uint8Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+extern int parcVarint_EqualsUint8(PARCVarint *varint, uint8_t value);
+
+extern void parcVarint_Destroy(PARCVarint **varintP);
+
+extern char *parcVarint_ToString(char **string, PARCVarint *varint);
+
+extern uint8_t parcVarint_AsUint8(const PARCVarint *varint);
+
+extern uint16_t parcVarint_AsUint16(const PARCVarint *varint);
+
+extern uint32_t parcVarint_AsUint32(const PARCVarint *varint);
+
+/**
+ * Produce the 16 low-order bits of this `PARCVarint` as a `uint8_t`.
+ *
+ * @param [in] varint The inpu instance of `PARCVarint`
+ * @return The 16 low-order bits as a `uint8_t`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint64_t parcVarint_AsUint64(const PARCVarint *varint);
+
+/**
+ * Return the value of the given `PARCVarint` cast as a `size_t`
+ *
+ * @param [in] varint The `PARCVarint` to cast as a `size_t`
+ *
+ * @return The given `PARCVarint` cast as a `size_t`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcVarint_AsSize(const PARCVarint *varint);
+
+/**
+ * Set the value of the given `PARCVarint` to the given value.
+ *
+ * @param [in,out] varint The `PARCVarint` to be modified
+ * @param [in] newValue The new value for the `PARCVarint`
+ * @return The modified `PARCVarint`.
+ */
+PARCVarint *parcVarint_Set(PARCVarint *varint, uint64_t newValue);
+
+/**
+ * Multiply the `PARCVarint`
+ *
+ * @param [in,out] varint The `PARCVarint` to be multiplied by the @p multiplicand
+ * @param [in] multiplicand The multiplicand to multiply by
+ * @return The `PARCVarint` used as input.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVarint *parcVarint_Multiply(PARCVarint *varint, int multiplicand);
+
+/**
+ * Divide the `PARCVarint` by a divisor
+ *
+ * @param [in,out] varint The `PARCVarint` to be divided by the @p divisor
+ * @param [in] divisor The divisor to use
+ * @return The `PARCVarint` used as input.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVarint *parcVarint_Divide(PARCVarint *varint, int divisor);
+/**
+ * Multiply the `PARCVarint`
+ *
+ * @param [in,out] varint The `PARCVarint` to which the @p addend should be added
+ * @param [in] addend The number to add to the `PARCVarint`
+ * @return The `PARCVarint` used as input.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVarint *parcVarint_Add(PARCVarint *varint, int addend);
+
+/**
+ * Subtract the @p subtrahend from the `PARCVarint`.
+ *
+ * @param [in,out] varint The `PARCVarint` from which to subtract the @p subtrahend
+ * @param [in] subtrahend The number to subtract from the `PARCVarint`
+ * @return The `PARCVarint` used as input.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVarint *parcVarint_Subtract(PARCVarint *varint, int subtrahend);
+#endif // libparc_parc_VarInt_h
diff --git a/libparc/parc/algol/parc_Vector.c b/libparc/parc/algol/parc_Vector.c
new file mode 100755
index 00000000..f5380eb7
--- /dev/null
+++ b/libparc/parc/algol/parc_Vector.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 <stdbool.h>
+#include <string.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_Vector.h>
+
+struct parc_vector {
+ const void *pointer;
+ size_t length;
+};
+
+PARCVector *
+parcVector_Create(const void *pointer, const size_t length)
+{
+ PARCVector *result = parcMemory_AllocateAndClear(sizeof(PARCVector));
+ if (result != NULL) {
+ parcVector_Init(result, pointer, length);
+ }
+
+ return result;
+}
+
+PARCVector *
+parcVector_Init(PARCVector *vector, const void *pointer, const size_t length)
+{
+ assertNotNull(vector, "Parameter must be a non-null PARCVector pointer");
+
+ vector->pointer = pointer;
+ vector->length = length;
+ return vector;
+}
+
+void
+parcVector_Destroy(PARCVector **vectorPtr)
+{
+ assertNotNull(vectorPtr, "Parameter must be a non-null PARCVector pointer");
+ PARCVector *vector = *vectorPtr;
+ assertNotNull(vector, "Vector is already free or was not set.\n");
+
+ parcMemory_Deallocate((void **) &vector);
+ *vectorPtr = NULL;
+}
+
+const void *
+parcVector_GetPointer(const PARCVector *vector)
+{
+ assertNotNull(vector, "Parameter must be a non-null PARCVector pointer.");
+ return vector->pointer;
+}
+
+size_t
+parcVector_GetLength(const PARCVector *vector)
+{
+ assertNotNull(vector, "Parameter must be a non-null PARCVector pointer.");
+
+ return vector->length;
+}
+
diff --git a/libparc/parc/algol/parc_Vector.h b/libparc/parc/algol/parc_Vector.h
new file mode 100755
index 00000000..825fc635
--- /dev/null
+++ b/libparc/parc/algol/parc_Vector.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 parc_Vector.h
+ * @ingroup datastructures
+ * @brief PARC Vector
+ * A Vector consists of a pointer and associated length in bytes of data in memory.
+ *
+ *
+ */
+#ifndef libparc_parc_Vector_h
+#define libparc_parc_Vector_h
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+struct parc_vector;
+
+/**
+ * A `PARCVector` is a tuple consisting of an address and a length.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef struct parc_vector PARCVector;
+
+/**
+ * Create a new `PARCVector` consisting of a pointer and a length.
+ *
+ * @param [in] pointer A pointer to memory.
+ * @param [in] length The length, in bytes.
+ * @return An allocated `PARCVector` structure.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVector *parcVector_Create(const void *pointer, const size_t length);
+
+/**
+ * Initialise the given `PARCVector` to the given values.
+ *
+ * @param [in,out] vector A pointer to the instance of `PARCVector` to initialize
+ * @param [in] pointer A pointer to the memory with which to initialize @p vector.
+ * @param [in] length The length of the @p pointer contents.
+ * @return The pointer to the input @p vector.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCVector *parcVector_Init(PARCVector *vector, const void *pointer, const size_t length);
+
+/**
+ * Get the memory pointer for this `PARCVector`.
+ *
+ * @param [in] vector A pointer to the instance of `PARCVector` from which to get the memory pointer.
+ * @return The memory pointer of @p vector
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const void *parcVector_GetPointer(const PARCVector *vector);
+
+/**
+ * Get the length of of the `PARCVector`
+ *
+ * @param [in] vector The `PARCVector` instance of interest.
+ * @return The length of @p vector.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t parcVector_GetLength(const PARCVector *vector);
+
+/**
+ * Destroy the instance of `PARCVector`
+ *
+ * @param [in,out] vector The pointer to the pointer to the `PARCVector` instance to destroy.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcVector_Destroy(PARCVector **vector);
+#endif // libparc_parc_Vector_h
diff --git a/libparc/parc/algol/test/.gitignore b/libparc/parc/algol/test/.gitignore
new file mode 100644
index 00000000..b520ab17
--- /dev/null
+++ b/libparc/parc/algol/test/.gitignore
@@ -0,0 +1,73 @@
+test_parc_ArrayList
+test_parc_AtomicInteger
+test_parc_Base64
+test_parc_BitVector
+test_parc_Buffer
+test_parc_BufferComposer
+test_parc_BufferDictionary
+test_parc_ByteArray
+test_parc_ByteBuffer
+test_parc_ByteBufferCodec
+test_parc_ByteBuffer_Codec
+test_parc_Clock
+test_parc_Deque
+test_parc_Dictionary
+test_parc_Digester
+test_parc_Digests
+test_parc_Digests
+test_parc_Display
+test_parc_ElasticBuffer
+test_parc_ElasticString
+test_parc_Environment
+test_parc_Event
+test_parc_EventBuffer
+test_parc_EventQueue
+test_parc_EventScheduler
+test_parc_EventSignal
+test_parc_EventSocket
+test_parc_EventTimer
+test_parc_Extent
+test_parc_ExtentArray
+test_parc_FileOutputStream
+test_parc_Hash
+test_parc_HashCode
+test_parc_HashCodeTable
+test_parc_HashMap
+test_parc_HashMap
+test_parc_HashTable
+test_parc_InputStream
+test_parc_Iterator
+test_parc_JSON
+test_parc_JSONArray
+test_parc_JSONPair
+test_parc_JSONParser
+test_parc_JSONValue
+test_parc_KeyValue
+test_parc_KeyedElement
+test_parc_LinkedList
+test_parc_List
+test_parc_Memory
+test_parc_Network
+test_parc_NewByteBuffer
+test_parc_Object
+test_parc_ObjectImpl
+test_parc_PathName
+test_parc_PointerArray
+test_parc_PriorityQueue
+test_parc_Properties
+test_parc_ReadOnlyBuffer
+test_parc_SafeMemory
+test_parc_SortedList
+test_parc_Stack
+test_parc_StdlibMemory
+test_parc_String
+test_parc_StructArray
+test_parc_Time
+test_parc_Tlv
+test_parc_TreeRedBlack
+test_parc_TreeMap
+test_parc_URI
+test_parc_VarInt
+test_parc_Varint
+test_parc_Vector
+test_parc_VectorArray
diff --git a/libparc/parc/algol/test/CMakeLists.txt b/libparc/parc/algol/test/CMakeLists.txt
new file mode 100644
index 00000000..4199f3de
--- /dev/null
+++ b/libparc/parc/algol/test/CMakeLists.txt
@@ -0,0 +1,76 @@
+# 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_parc_ArrayList
+ test_parc_AtomicInteger
+ test_parc_Base64
+ test_parc_BitVector
+ test_parc_Buffer
+ test_parc_BufferChunker
+ test_parc_BufferComposer
+ test_parc_ByteArray
+ test_parc_Clock
+ test_parc_Chunker
+ test_parc_Deque
+ test_parc_Dictionary
+ test_parc_Display
+ test_parc_Environment
+ test_parc_Event
+ test_parc_EventBuffer
+ test_parc_EventQueue
+ test_parc_EventScheduler
+ test_parc_EventSignal
+ test_parc_EventSocket
+ test_parc_EventTimer
+ test_parc_File
+ test_parc_FileChunker
+ test_parc_FileInputStream
+ test_parc_FileOutputStream
+ test_parc_Hash
+ test_parc_HashCode
+ test_parc_HashCodeTable
+ test_parc_HashMap
+ test_parc_InputStream
+ test_parc_Iterator
+ test_parc_JSON
+ test_parc_JSONArray
+ test_parc_JSONPair
+ test_parc_JSONParser
+ test_parc_JSONValue
+ test_parc_KeyValue
+ test_parc_KeyedElement
+ test_parc_LinkedList
+ test_parc_List
+ test_parc_Memory
+ test_parc_Network
+ test_parc_Object
+ test_parc_PathName
+ test_parc_PriorityQueue
+ test_parc_Properties
+ test_parc_RandomAccessFile
+ test_parc_ReadOnlyBuffer
+ test_parc_SafeMemory
+ test_parc_SortedList
+ test_parc_Stack
+ test_parc_StdlibMemory
+ test_parc_String
+ test_parc_Time
+ test_parc_TreeMap
+ test_parc_TreeRedBlack
+ test_parc_URI
+ test_parc_URIAuthority
+ test_parc_URIPath
+ test_parc_URISegment
+ test_parc_Varint
+ test_parc_Vector
+ )
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
+
diff --git a/libparc/parc/algol/test/_test_parc_URI.h b/libparc/parc/algol/test/_test_parc_URI.h
new file mode 100644
index 00000000..01d3afae
--- /dev/null
+++ b/libparc/parc/algol/test/_test_parc_URI.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.
+ */
+
+/*
+ * _test_parc_URI.h
+ * PARC Algol
+ */
+
+#ifndef PARC_Algol__test_parc_URI_h
+#define PARC_Algol__test_parc_URI_h
+
+#define URI_SCHEME "lci"
+
+#define URI_AUTHORITY_USERINFO "user:pass"
+#define URI_AUTHORITY_USERINFO_2 "user2:pass2"
+#define URI_AUTHORITY_HOSTNAME "parc.com"
+#define URI_AUTHORITY_HOSTNAME_2 "xerox.com"
+#define URI_AUTHORITY_LITERAL_HOSTNAME "127.0.0.1"
+#define URI_AUTHORITY_LITERAL_HOSTNAME6 "[::0]"
+#define URI_AUTHORITY_LITERAL_HOSTNAME6_2 "[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]"
+#define URI_AUTHORITY_PORT_1 "1234"
+#define URI_AUTHORITY_PORT_2 "5678"
+
+#define URI_AUTHORITY URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_HOSTNAME ":" URI_AUTHORITY_PORT_1
+#define URI_AUTHORITY_DIFFERENT_PORT URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_HOSTNAME ":" URI_AUTHORITY_PORT_2
+#define URI_AUTHORITY_DIFFERENT_HOST URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_HOSTNAME_2 ":" URI_AUTHORITY_PORT_1
+#define URI_AUTHORITY_LITERAL_HOST URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_LITERAL_HOSTNAME ":" URI_AUTHORITY_PORT_1
+#define URI_AUTHORITY_LITERAL_HOST6 URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_LITERAL_HOSTNAME6 ":" URI_AUTHORITY_PORT_1
+#define URI_AUTHORITY_LITERAL_HOST6_2 URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_LITERAL_HOSTNAME6_2 ":" URI_AUTHORITY_PORT_1
+#define URI_AUTHORITY_DIFFERENT_USER URI_AUTHORITY_USERINFO_2 "@" URI_AUTHORITY_HOSTNAME ":" URI_AUTHORITY_PORT_1
+
+#define URI_PATH_SEGMENT "%00%01%02-.%03%04_%05%06%07%08%09abcdefghijklmnopqrstuvwxyz"
+#define URI_PATH_SEGMENT_WITH_SLASHES URI_PATH_SEGMENT "//////"
+
+#define URI_PATH "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT
+
+#define URI_QUERY "x=1&y=2&z=3"
+
+#define URI_FRAGMENT "alphabetagamma"
+
+#define URI_FULL URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH "?" URI_QUERY "#" URI_FRAGMENT
+
+char *TEST_URI_SCHEME = URI_SCHEME;
+char *TEST_URI_AUTHORITY = URI_AUTHORITY;
+#endif // PARC_Algol__test_parc_URI_h
diff --git a/libparc/parc/algol/test/data.json b/libparc/parc/algol/test/data.json
new file mode 100644
index 00000000..a146f6ff
--- /dev/null
+++ b/libparc/parc/algol/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/libparc/parc/algol/test/test_parc_ArrayList.c b/libparc/parc/algol/test/test_parc_ArrayList.c
new file mode 100755
index 00000000..9e387a28
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_ArrayList.c
@@ -0,0 +1,658 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_ArrayList.c"
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <parc/algol/parc_Buffer.h>
+
+LONGBOW_TEST_RUNNER(PARC_ArrayList)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(Errors);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(PARC_ArrayList)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(PARC_ArrayList)
+{
+ 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;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Add);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_AddAll);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Destroy);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_CustomDestroyer);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Equals_Contract);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Equals_Contract_Deep);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_FromInitialCapacity);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Get);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_New);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Size);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_ArrayList_IsEmpty);
+}
+
+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 %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Add)
+{
+ PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+
+ parcArrayList_Add(array, 0);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(1 == actual, "Expected=%d, actual=%zu", 1, actual);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_AddAll)
+{
+ PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+
+ void *elements[] = {
+ strdup("a"),
+ strdup("b"),
+ strdup("c"),
+ };
+
+ parcArrayList_AddAll(array, elements, 3);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Copy)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *copy = parcArrayList_Copy(array);
+ assertTrue(parcArrayList_Equals(array, copy), "Expected arrays to be equal.");
+
+ parcArrayList_Destroy(&copy);
+ parcArrayList_Destroy(&array);
+}
+
+static void
+testCustomDestroyer(void **bufferVoidPtr)
+{
+ PARCBuffer **bufferPtr = (PARCBuffer **) bufferVoidPtr;
+ parcBuffer_Release(bufferPtr);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_CustomDestroyer)
+{
+ size_t before = parcMemory_Outstanding();
+
+ PARCArrayList *array = parcArrayList_Create(testCustomDestroyer);
+ PARCBuffer *buffer = parcBuffer_Allocate(20);
+ parcArrayList_Add(array, parcBuffer_Acquire(buffer));
+ parcBuffer_Release(&buffer);
+ parcArrayList_Destroy(&array);
+
+ size_t after = parcMemory_Outstanding();
+
+ assertTrue(before == after, "Memory imbalance after using custom destroy, expected %zu got %zu", before, after);
+}
+
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Destroy)
+{
+ PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+
+ parcArrayList_Destroy(&array);
+ assertNull(array, "Expected null.");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Equals_Empty)
+{
+ PARCArrayList *a = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ PARCArrayList *b = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ assertTrue(parcArrayList_Equals(a, b), "Equal values were expected to be equal");
+
+ parcArrayList_Destroy(&a);
+ parcArrayList_Destroy(&b);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Equals_Same)
+{
+ PARCArrayList *a = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ assertTrue(parcArrayList_Equals(a, a), "Expected the same array list to be equal to itself.");
+
+ parcArrayList_Destroy(&a);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Equals_Contract)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+ char d[] = "potato";
+
+ PARCArrayList *x = parcArrayList_Create(NULL);
+ parcArrayList_Add(x, a);
+ parcArrayList_Add(x, b);
+ parcArrayList_Add(x, c);
+
+ PARCArrayList *y = parcArrayList_Create(NULL);
+ parcArrayList_Add(y, a);
+ parcArrayList_Add(y, b);
+ parcArrayList_Add(y, c);
+
+ PARCArrayList *z = parcArrayList_Create(NULL);
+ parcArrayList_Add(z, a);
+ parcArrayList_Add(z, b);
+ parcArrayList_Add(z, c);
+
+ PARCArrayList *u1 = parcArrayList_Create(NULL);
+ parcArrayList_Add(u1, a);
+ parcArrayList_Add(u1, b);
+
+ PARCArrayList *u2 = parcArrayList_Create(NULL);
+ parcArrayList_Add(u1, a);
+ parcArrayList_Add(u2, b);
+ parcArrayList_Add(u2, c);
+ parcArrayList_Add(u2, c);
+
+ PARCArrayList *u3 = parcArrayList_Create(NULL);
+ parcArrayList_Add(u3, a);
+ parcArrayList_Add(u3, b);
+ parcArrayList_Add(u3, d);
+
+ parcObjectTesting_AssertEqualsFunction(parcArrayList_Equals, x, y, z, u1, u2, u3);
+
+ parcArrayList_Destroy(&x);
+ parcArrayList_Destroy(&y);
+ parcArrayList_Destroy(&z);
+ parcArrayList_Destroy(&u1);
+ parcArrayList_Destroy(&u2);
+ parcArrayList_Destroy(&u3);
+}
+
+static bool
+stringEquals(void *x, void *y)
+{
+ return strcmp((char *) x, (char *) y) == 0;
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Equals_Contract_Deep)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+ char d[] = "potato";
+
+ PARCArrayList *x = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(x, a);
+ parcArrayList_Add(x, b);
+ parcArrayList_Add(x, c);
+
+ PARCArrayList *y = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(y, a);
+ parcArrayList_Add(y, b);
+ parcArrayList_Add(y, c);
+
+ PARCArrayList *z = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(z, a);
+ parcArrayList_Add(z, b);
+ parcArrayList_Add(z, c);
+
+ PARCArrayList *u1 = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(u1, a);
+ parcArrayList_Add(u1, b);
+
+ PARCArrayList *u2 = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(u2, a);
+ parcArrayList_Add(u2, b);
+ parcArrayList_Add(u2, c);
+ parcArrayList_Add(u2, c);
+
+ PARCArrayList *u3 = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(u3, a);
+ parcArrayList_Add(u3, b);
+ parcArrayList_Add(u3, d);
+
+ parcObjectTesting_AssertEqualsFunction(parcArrayList_Equals, x, y, z, u1, u2, u3);
+
+ parcArrayList_Destroy(&x);
+ parcArrayList_Destroy(&y);
+ parcArrayList_Destroy(&z);
+ parcArrayList_Destroy(&u1);
+ parcArrayList_Destroy(&u2);
+ parcArrayList_Destroy(&u3);
+}
+
+LONGBOW_TEST_CASE(Local, PARC_ArrayList_EnsureRemaining_Empty)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ size_t expected = 4;
+ _ensureRemaining(array, expected);
+
+ size_t actual = _remaining(array);
+
+ assertTrue(actual >= expected, "Expected >= %zd, actual=%zd", expected, actual);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Local, PARC_ArrayList_EnsureRemaining_NonEmpty)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, 0);
+
+ size_t expected = 5;
+ _ensureRemaining(array, expected);
+
+ size_t actual = _remaining(array);
+
+ assertTrue(actual >= expected, "Expected >= %zd, actual=%zd", expected, actual);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_FromInitialCapacity)
+{
+ PARCArrayList *array = parcArrayList_Create_Capacity(NULL, parcArrayList_StdlibFreeFunction, 10);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(0 == actual, "Expected=%d, actual=%zu", 0, actual);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Get)
+{
+ PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+
+ char *expected = strdup("Hello World");
+ parcArrayList_Add(array, expected);
+
+ char *actual = parcArrayList_Get(array, 0);
+
+ assertTrue(expected == actual, "Expected=%p, actual=%p", (void *) expected, (void *) actual);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_New)
+{
+ PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ size_t size = parcArrayList_Size(array);
+ assertTrue(0 == size, "Expected %d actual=%zu", 0, size);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Size)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, 0);
+
+ size_t size = parcArrayList_Size(array);
+ assertTrue(1 == size, "Expected %d actual=%zu", 1, size);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_IsEmpty)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ assertTrue(parcArrayList_IsEmpty(array), "Expected a new array to be empty.");
+
+ parcArrayList_Add(array, 0);
+ assertFalse(parcArrayList_IsEmpty(array), "Expected an array with more than zero elements to be empty.");
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ parcArrayList_Add(array, (void *) 1);
+ parcArrayList_Add(array, (void *) 2);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual);
+
+ parcArrayList_InsertAtIndex(array, 1, (void *) 3);
+
+ actual = parcArrayList_Size(array);
+ assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual);
+
+ void *element0 = parcArrayList_Get(array, 0);
+ assertTrue(element0 == (void *) 1, "Element 1 moved?");
+
+ void *element1 = parcArrayList_Get(array, 1);
+ assertTrue(element1 == (void *) 3, "Element 1 moved?");
+
+ void *element2 = parcArrayList_Get(array, 2);
+ assertTrue(element2 == (void *) 2, "Element 1 moved?");
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_Empty)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ parcArrayList_InsertAtIndex(array, 0, (void *) 3);
+
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(1 == actual, "Expected=%d, actual=%zu", 1, actual);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_First)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ parcArrayList_Add(array, (void *) 1);
+ parcArrayList_InsertAtIndex(array, 0, (void *) 2);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual);
+
+ void *element0 = parcArrayList_Get(array, 0);
+ assertTrue(element0 == (void *) 2, "Element 1 moved?");
+
+ void *element1 = parcArrayList_Get(array, 1);
+ assertTrue(element1 == (void *) 1, "Element 1 moved?");
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_InsertAtIndex_Last)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ parcArrayList_Add(array, (void *) 1);
+ parcArrayList_Add(array, (void *) 2);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual);
+
+ parcArrayList_InsertAtIndex(array, 2, (void *) 3);
+
+ actual = parcArrayList_Size(array);
+ assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual);
+
+ void *element0 = parcArrayList_Get(array, 0);
+ assertTrue(element0 == (void *) 1, "Element 1 moved?");
+
+ void *element1 = parcArrayList_Get(array, 1);
+ assertTrue(element1 == (void *) 2, "Element 1 moved?");
+
+ void *element2 = parcArrayList_Get(array, 2);
+ assertTrue(element2 == (void *) 3, "Element 1 moved?");
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex_First)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, b);
+ parcArrayList_Add(expected, c);
+
+ void *removedElement = parcArrayList_RemoveAtIndex(array, 0);
+
+ assertTrue(removedElement == a, "Expected ");
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, a);
+ parcArrayList_Add(expected, c);
+
+ void *removedElement = parcArrayList_RemoveAtIndex(array, 1);
+
+ assertTrue(removedElement == b, "Expected ");
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_Remove_AtIndex_Last)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, a);
+ parcArrayList_Add(expected, b);
+
+ void *removedElement = parcArrayList_RemoveAtIndex(array, 2);
+
+ assertTrue(removedElement == c, "Expected ");
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex_First)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, b);
+ parcArrayList_Add(expected, c);
+
+ parcArrayList_RemoveAndDestroyAtIndex(array, 0);
+
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, a);
+ parcArrayList_Add(expected, c);
+
+ parcArrayList_RemoveAndDestroyAtIndex(array, 1);
+
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_ArrayList_RemoveAndDestroy_AtIndex_Last)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, a);
+ parcArrayList_Add(expected, b);
+
+ parcArrayList_RemoveAndDestroyAtIndex(array, 2);
+
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, PARC_ArrayList_EnsureRemaining_Empty);
+ LONGBOW_RUN_TEST_CASE(Local, PARC_ArrayList_EnsureRemaining_NonEmpty);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, PARC_ArrayList_InsertAtIndex_OutOfCapacity);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ longBowTestCase_SetClipBoardData(testCase, array);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ PARCArrayList *array = longBowTestCase_GetClipBoardData(testCase);
+ parcArrayList_Destroy(&array);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, PARC_ArrayList_InsertAtIndex_OutOfCapacity, .event = &LongBowAssertEvent)
+{
+ PARCArrayList *array = longBowTestCase_GetClipBoardData(testCase);
+
+ parcArrayList_Add(array, (void *) 1);
+ parcArrayList_Add(array, (void *) 2);
+
+ parcArrayList_InsertAtIndex(array, 200, (void *) 3);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARC_ArrayList);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_AtomicInteger.c b/libparc/parc/algol/test/test_parc_AtomicInteger.c
new file mode 100644
index 00000000..9bd1b99a
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_AtomicInteger.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_AtomicInteger.c"
+
+#include <inttypes.h>
+#include <stdio.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+LONGBOW_TEST_RUNNER(test_parc_AtomicInteger)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Threaded);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_parc_AtomicInteger)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_AtomicInteger)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicInteger_Uint32Increment);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicInteger_Uint32Decrement);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicInteger_Uint64Increment);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicInteger_Uint64Decrement);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicInteger_Uint32Increment)
+{
+ uint32_t value = 0;
+ parcAtomicInteger_Uint32Increment(&value);
+ assertTrue(value == 1, "Expected 1, actual, %u", value);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicInteger_Uint32Decrement)
+{
+ uint32_t value = 0;
+ parcAtomicInteger_Uint32Increment(&value);
+ assertTrue(value == 1, "Expected 1, actual, %u", value);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicInteger_Uint64Increment)
+{
+ uint64_t value = 0;
+ parcAtomicInteger_Uint64Increment(&value);
+ assertTrue(value == 1, "Expected 1, actual, %" PRIu64 "", value);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicInteger_Uint64Decrement)
+{
+ uint64_t value = 0;
+ parcAtomicInteger_Uint64Increment(&value);
+ assertTrue(value == 1, "Expected 1, actual, %" PRIu64 "", value);
+}
+
+LONGBOW_TEST_FIXTURE(Threaded)
+{
+ LONGBOW_RUN_TEST_CASE(Threaded, collaborative);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Threaded)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Threaded)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static void *
+collaborator_A(void *data)
+{
+ uint32_t *valuePointer = (uint32_t *) data;
+ uint32_t contribution = 0;
+ while (*valuePointer < 1000000) {
+ parcAtomicInteger_Uint32Increment(valuePointer);
+ contribution++;
+ }
+ printf("A contribution %d\n", contribution);
+ pthread_exit((void *) NULL);
+}
+
+static void *
+collaborator_B(void *data)
+{
+ uint32_t *valuePointer = (uint32_t *) data;
+
+ uint32_t contribution = 0;
+ while (*valuePointer < 1000000) {
+ parcAtomicInteger_Uint32Increment(valuePointer);
+ contribution++;
+ }
+
+ printf("B contribution %d\n", contribution);
+ pthread_exit((void *) NULL);
+}
+
+LONGBOW_TEST_CASE(Threaded, collaborative)
+{
+ uint32_t value = 0;
+
+ pthread_t thread_A;
+ pthread_t thread_B;
+
+ pthread_create(&thread_A, NULL, collaborator_A, &value);
+ pthread_create(&thread_B, NULL, collaborator_B, &value);
+
+ pthread_join(thread_A, NULL);
+ pthread_join(thread_B, NULL);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_AtomicInteger);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Base64.c b/libparc/parc/algol/test/test_parc_Base64.c
new file mode 100755
index 00000000..4509ded3
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Base64.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/unit-test.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Base64.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(parc_Base64)
+{
+ // 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(parc_Base64)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Base64)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcBase64_Decode);
+ LONGBOW_RUN_TEST_CASE(Global, parcBase64_Decode_Linefeeds);
+ LONGBOW_RUN_TEST_CASE(Global, parcBase64_Encode);
+ LONGBOW_RUN_TEST_CASE(Global, parcBase64_Encode_Binary);
+}
+
+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 %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static struct testvector_s {
+ char *plaintext;
+ char *encoded;
+} testvector[] = {
+ // Test vectors from RFC 4648
+ { .plaintext = "", .encoded = "" },
+ { .plaintext = "f", .encoded = "Zg==" },
+ { .plaintext = "fo", .encoded = "Zm8=" },
+ { .plaintext = "foo", .encoded = "Zm9v" },
+ { .plaintext = "foob", .encoded = "Zm9vYg==" },
+ { .plaintext = "fooba", .encoded = "Zm9vYmE=" },
+ { .plaintext = "foobar", .encoded = "Zm9vYmFy" },
+ { .plaintext = NULL, .encoded = NULL }
+};
+
+LONGBOW_TEST_CASE(Global, parcBase64_Decode)
+{
+ int i = 0;
+ while (testvector[i].plaintext != NULL) {
+ PARCBufferComposer *input = parcBufferComposer_Create();
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ PARCBufferComposer *output = parcBufferComposer_Create();
+
+ parcBufferComposer_PutString(input, testvector[i].encoded);
+ PARCBuffer *inputBuffer = parcBufferComposer_ProduceBuffer(input);
+ parcBufferComposer_PutString(truth, testvector[i].plaintext);
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ parcBase64_Decode(output, parcBufferComposer_GetBuffer(input));
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "encoding, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ i++;
+
+ parcBuffer_Release(&inputBuffer);
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&input);
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, parcBase64_Decode_Linefeeds)
+{
+ PARCBufferComposer *input = parcBufferComposer_Create();
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ PARCBufferComposer *output = parcBufferComposer_Create();
+
+ char plaintext[] = "It was a dark and stormy night, and all through the code not bit was stirring.\x0A";
+ char encoded_with_crlf[] = "SXQg" "\x0D\x0A" "d2FzIGEgZGFyayBhbmQgc3Rvcm15IG5pZ2h0LCBhbmQgYWxsIHRocm91Z2gg" "\x0D\x0A" "dGhlIGNvZGUgbm90IGJpdCB3YXMgc3RpcnJpbmcuCg==";
+
+ parcBufferComposer_PutString(input, encoded_with_crlf);
+ PARCBuffer *inputBuffer = parcBufferComposer_ProduceBuffer(input);
+
+ parcBufferComposer_PutString(truth, plaintext);
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ parcBase64_Decode(output, parcBufferComposer_GetBuffer(input));
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "encoding, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ parcBuffer_Release(&inputBuffer);
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&input);
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+}
+
+
+LONGBOW_TEST_CASE(Global, parcBase64_Encode)
+{
+ int i = 0;
+ while (testvector[i].plaintext != NULL) {
+ PARCBufferComposer *input = parcBufferComposer_Create();
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ PARCBufferComposer *output = parcBufferComposer_Create();
+
+ parcBufferComposer_PutString(input, testvector[i].plaintext);
+ PARCBuffer *inputBuffer = parcBufferComposer_ProduceBuffer(input);
+ parcBufferComposer_PutString(truth, testvector[i].encoded);
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ parcBase64_Encode(output, parcBufferComposer_GetBuffer(input));
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "encoding, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ i++;
+
+ parcBuffer_Release(&inputBuffer);
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&input);
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, parcBase64_Encode_Binary)
+{
+ uint8_t zero[] = { 0 };
+
+ // 1 2 3 4 5 6 7
+ char *truthvector[] = { "AA==", "AAA=", "AAAA", "AAAAAA==", "AAAAAAA=", "AAAAAAAA", "AAAAAAAAAA==" };
+
+ for (int i = 0; i < sizeof(truthvector) / sizeof(truthvector[0]); i++) {
+ PARCBufferComposer *input = parcBufferComposer_Create();
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ PARCBufferComposer *output = parcBufferComposer_Create();
+
+ parcBufferComposer_PutArray(truth, (uint8_t *) truthvector[i], strlen(truthvector[i]));
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ // just keep apending a zero to make it longer
+ parcBuffer_SetLimit(parcBufferComposer_GetBuffer(input), parcBuffer_Capacity(parcBufferComposer_GetBuffer(input)));
+ parcBuffer_SetPosition(parcBufferComposer_GetBuffer(input), i);
+ parcBufferComposer_PutArray(input, zero, 1);
+ PARCBuffer *inputBuffer = parcBufferComposer_ProduceBuffer(input);
+
+ parcBase64_Encode(output, parcBufferComposer_GetBuffer(input));
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "encoding, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ parcBuffer_Release(&inputBuffer);
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&input);
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+ }
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, encodeWithPad_0);
+ LONGBOW_RUN_TEST_CASE(Local, encodeWithPad_1);
+ LONGBOW_RUN_TEST_CASE(Local, encodeWithPad_2);
+ LONGBOW_RUN_TEST_CASE(Local, decode_invalid);
+ LONGBOW_RUN_TEST_CASE(Local, decode_1);
+ LONGBOW_RUN_TEST_CASE(Local, decode_2);
+ LONGBOW_RUN_TEST_CASE(Local, decode_3);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/**
+ * This will encode "foo"
+ */
+LONGBOW_TEST_CASE(Local, encodeWithPad_0)
+{
+ PARCBufferComposer *output = parcBufferComposer_Create();
+ uint8_t input[] = "foobar";
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ parcBufferComposer_PutString(truth, "Zm9v");
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ _encodeWithPad(output, input, 0);
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "Failed 3-byte encode, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+}
+
+/**
+ * This will encode "fo" because we tell it there's 1 pad byte
+ */
+LONGBOW_TEST_CASE(Local, encodeWithPad_1)
+{
+ PARCBufferComposer *output = parcBufferComposer_Create();
+ uint8_t input[] = "foobar";
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ parcBufferComposer_PutString(truth, "Zm8=");
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ _encodeWithPad(output, input, 1);
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "Failed 3-byte encode, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+}
+
+/**
+ * This will encode "f" because we tell it there's 2 pad byte
+ */
+LONGBOW_TEST_CASE(Local, encodeWithPad_2)
+{
+ PARCBufferComposer *output = parcBufferComposer_Create();
+ uint8_t input[] = "foobar";
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ parcBufferComposer_PutString(truth, "Zg==");
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ _encodeWithPad(output, input, 2);
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "Failed 3-byte encode, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+}
+
+
+LONGBOW_TEST_CASE(Local, decode_1)
+{
+ PARCBufferComposer *output = parcBufferComposer_Create();
+ uint8_t input[] = "Zg==";
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ parcBufferComposer_PutString(truth, "f");
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ bool success = _decode(output, input);
+ assertTrue(success, "Valid base64 failed decode");
+
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "Failed 3-byte encode, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Local, decode_2)
+{
+ PARCBufferComposer *output = parcBufferComposer_Create();
+ uint8_t input[] = "Zm8=";
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ parcBufferComposer_PutString(truth, "fo");
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ bool success = _decode(output, input);
+ assertTrue(success, "Valid base64 failed decode");
+
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "Failed 3-byte encode, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Local, decode_3)
+{
+ PARCBufferComposer *output = parcBufferComposer_Create();
+ uint8_t input[] = "Zm9v";
+ PARCBufferComposer *truth = parcBufferComposer_Create();
+ parcBufferComposer_PutString(truth, "foo");
+ PARCBuffer *truthBuffer = parcBufferComposer_ProduceBuffer(truth);
+
+ bool success = _decode(output, input);
+ assertTrue(success, "Valid base64 failed decode");
+ PARCBuffer *outputBuffer = parcBufferComposer_ProduceBuffer(output);
+
+ assertTrue(parcBuffer_Equals(truthBuffer, outputBuffer),
+ "Failed 3-byte encode, expected '%s' got '%s'",
+ parcBuffer_ToHexString(truthBuffer),
+ parcBuffer_ToHexString(outputBuffer));
+
+ parcBuffer_Release(&truthBuffer);
+ parcBuffer_Release(&outputBuffer);
+
+ parcBufferComposer_Release(&output);
+ parcBufferComposer_Release(&truth);
+}
+
+LONGBOW_TEST_CASE(Local, decode_invalid)
+{
+ PARCBufferComposer *output = parcBufferComposer_Create();
+ uint8_t input[] = "@@@@";
+
+ bool success = _decode(output, input);
+ assertFalse(success, "Invalid base64 somehow decoded");
+
+ parcBufferComposer_Release(&output);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Base64);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_BitVector.c b/libparc/parc/algol/test/test_parc_BitVector.c
new file mode 100755
index 00000000..9a4d0806
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_BitVector.c
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/unit-test.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_BitVector.c"
+
+#include <stdio.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <limits.h>
+
+LONGBOW_TEST_RUNNER(parc_BitVector)
+{
+ // 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(parc_BitVector)
+{
+ 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_BitVector)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Create_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_SetClear);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_SetVector);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Reset);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_ClearVector);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_NextBitSet);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Get);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Contains);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Set);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_And);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Or);
+ LONGBOW_RUN_TEST_CASE(Global, parcBitVector_Shift);
+}
+
+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 %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Create_Release)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+ PARCBitVector *reference = parcBitVector;
+ parcBitVector_Acquire(reference);
+ parcBitVector_Release(&parcBitVector);
+ parcBitVector_Release(&reference);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Set)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Create created a non-empty vector");
+
+ parcBitVector_Set(parcBitVector, 0);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 1, "Expect number of bits set to be 1");
+ assertTrue(parcBitVector->firstBitSet == 0, "Expect first bit set to be 0");
+ assertTrue(parcBitVector->bitLength == 8, "Expect the bitLength to be 8");
+ assertTrue(parcBitVector->bitArray[0] == (uint8_t) 1, "Expect the bitArray as a unsigned char to be = 1");
+
+ parcBitVector_Set(parcBitVector, 7);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 2, "Expect number of bits set to be 2");
+ assertTrue(parcBitVector->firstBitSet == 0, "Expect first bit set to be 0");
+ assertTrue(parcBitVector->bitLength == 8, "Expect the bitLength to be 8");
+ assertTrue(parcBitVector->bitArray[0] == (uint8_t) 0x81, "Expect the bitArray as a unsigned char to be = 0x81");
+
+ parcBitVector_Set(parcBitVector, 8);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 3, "Expect number of bits set to be 3");
+ assertTrue(parcBitVector->firstBitSet == 0, "Expect first bit set to be 0");
+ assertTrue(parcBitVector->bitLength == 16, "Expect the bitLength to be 16");
+ assertTrue(parcBitVector->bitArray[0] == (uint8_t) 0x81, "Expect the bitArray as a unsigned char to be = 0x81");
+ assertTrue(parcBitVector->bitArray[1] == (uint8_t) 0x1, "Expect the bitArray as a unsigned char to be = 0x1");
+
+ parcBitVector_Release(&parcBitVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_And)
+{
+ PARCBitVector *vector1 = parcBitVector_Create();
+ PARCBitVector *vector2 = parcBitVector_Create();
+
+ parcBitVector_Set(vector1, 1);
+ parcBitVector_Set(vector1, 2);
+ parcBitVector_Set(vector1, 10);
+ parcBitVector_Set(vector2, 2);
+ parcBitVector_Set(vector2, 1);
+ parcBitVector_Set(vector2, 20);
+
+ PARCBitVector *result = parcBitVector_And(vector1, vector2);
+
+ assertTrue(parcBitVector_NumberOfBitsSet(result) == 2, "AND vector not equal to expected results");
+ parcBitVector_Release(&result);
+
+ result = parcBitVector_And(vector1, NULL);
+ assertTrue(parcBitVector_NumberOfBitsSet(result) == 0, "AND vector not equal to expected results");
+ parcBitVector_Release(&result);
+
+ result = parcBitVector_And(NULL, vector2);
+ assertTrue(parcBitVector_NumberOfBitsSet(result) == 0, "AND vector not equal to expected results");
+ parcBitVector_Release(&result);
+
+ result = parcBitVector_And(NULL, NULL);
+ assertTrue(parcBitVector_NumberOfBitsSet(result) == 0, "AND vector not equal to expected results");
+ parcBitVector_Release(&result);
+
+ parcBitVector_Release(&vector1);
+ parcBitVector_Release(&vector2);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Or)
+{
+ PARCBitVector *vector1 = parcBitVector_Create();
+ PARCBitVector *vector2 = parcBitVector_Create();
+
+ parcBitVector_Set(vector1, 1);
+ parcBitVector_Set(vector1, 2);
+ parcBitVector_Set(vector1, 10);
+ parcBitVector_Set(vector2, 2);
+ parcBitVector_Set(vector2, 1);
+ parcBitVector_Set(vector2, 20);
+
+ PARCBitVector *result = parcBitVector_Or(vector1, vector2);
+
+ assertTrue(parcBitVector_Contains(result, vector1), "Vector contents not included in OR operation results");
+ assertTrue(parcBitVector_Contains(result, vector2), "Vector contents not included in OR operation results");
+ assertTrue(parcBitVector_NumberOfBitsSet(result) == 4, "OR vector not equal to expected results");
+ parcBitVector_Release(&result);
+
+ result = parcBitVector_Or(vector1, NULL);
+ assertTrue(parcBitVector_Equals(result, vector1), "OR vector not equal to expected results");
+ parcBitVector_Release(&result);
+
+ result = parcBitVector_Or(NULL, vector2);
+ assertTrue(parcBitVector_Equals(result, vector2), "OR vector not equal to expected results");
+ parcBitVector_Release(&result);
+
+ result = parcBitVector_Or(NULL, NULL);
+ assertTrue(parcBitVector_NumberOfBitsSet(result) == 0, "OR vector not equal to expected results");
+ parcBitVector_Release(&result);
+
+ parcBitVector_Release(&vector1);
+ parcBitVector_Release(&vector2);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Shift)
+{
+ PARCBitVector *vector = parcBitVector_Create();
+
+ parcBitVector_Set(vector, 0); // should drop off on left shift
+ parcBitVector_Set(vector, 11);
+ parcBitVector_Set(vector, 12);
+ parcBitVector_Set(vector, 13);
+ parcBitVector_Set(vector, 22);
+ parcBitVector_LeftShift(vector, 10);
+ parcBitVector_RightShift(vector, 10);
+ assertTrue(parcBitVector_NextBitSet(vector, 0) == 11, "Shift operations failed");
+ assertTrue(parcBitVector_NextBitSet(vector, 12) == 12, "Shift operations failed");
+ assertTrue(parcBitVector_NextBitSet(vector, 14) == 22, "Shift operations failed");
+ assertTrue(parcBitVector_NumberOfBitsSet(vector) == 4, "Shift operations failed to drop first bit on left shift");
+ parcBitVector_Release(&vector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_SetClear)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Create created a non-empty vector");
+
+ parcBitVector_Set(parcBitVector, 10);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 1, "parcBitVector_Set failed");
+
+ parcBitVector_Clear(parcBitVector, 10);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Clear failed");
+
+ parcBitVector_Clear(parcBitVector, 20);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Clear failed");
+
+ parcBitVector_Release(&parcBitVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_SetVector)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+ PARCBitVector *setVector = parcBitVector_Create();
+ parcBitVector_Set(parcBitVector, 1);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 1, "parcBitVector_Set failed");
+
+ parcBitVector_Set(setVector, 20);
+ parcBitVector_SetVector(parcBitVector, setVector);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 2, "parcBitVector_SetVector failed");
+ assertTrue(parcBitVector_NextBitSet(parcBitVector, 0) == 1, "parcBitVector_Set failed to set bit 1");
+ assertTrue(parcBitVector_NextBitSet(parcBitVector, 2) == 20, "parcBitVector_SetVector failed to set bit 20");
+
+ parcBitVector_Set(setVector, 10);
+ parcBitVector_SetVector(parcBitVector, setVector);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 3, "parcBitVector_SetVector failed");
+ parcBitVector_Release(&parcBitVector);
+ parcBitVector_Release(&setVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Reset)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+
+ // Reset and empty vector test
+ parcBitVector_Reset(parcBitVector);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Reset failed");
+
+ parcBitVector_Set(parcBitVector, 1);
+ parcBitVector_Set(parcBitVector, 42);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 2, "parcBitVector_Set failed");
+ assertTrue(parcBitVector->bitLength == 48, "Expected a bitLength of 48");
+
+ parcBitVector_Reset(parcBitVector);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Reset failed");
+ assertTrue(parcBitVector->bitLength == 48, "Expected a bitLength of 48");
+
+ parcBitVector_Release(&parcBitVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_ClearVector)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+
+ PARCBitVector *setVector = parcBitVector_Create();
+ parcBitVector_Set(parcBitVector, 1);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 1, "parcBitVector_Set failed to set bit");
+
+ parcBitVector_Set(setVector, 1);
+ parcBitVector_Set(setVector, 20);
+ parcBitVector_ClearVector(parcBitVector, setVector);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_ClearVector failed to clear vector");
+
+ parcBitVector_Set(parcBitVector, 12);
+ parcBitVector_Set(parcBitVector, 17);
+ parcBitVector_ClearVector(parcBitVector, parcBitVector);
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_ClearVector failed to clear vector");
+
+ parcBitVector_Release(&parcBitVector);
+ parcBitVector_Release(&setVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_NextBitSet)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Create created a non-empty vector");
+
+ int nextBit = parcBitVector_NextBitSet(parcBitVector, 0);
+ assertTrue(nextBit == -1, "parcBitVector_NextBitSet should have failed (%d)", nextBit);
+
+ parcBitVector_Set(parcBitVector, 10);
+ nextBit = parcBitVector_NextBitSet(parcBitVector, 0);
+ assertTrue(nextBit == 10, "parcBitVector_NextBitSet failed (%d)", nextBit);
+
+ nextBit = parcBitVector_NextBitSet(parcBitVector, 20);
+ assertTrue(nextBit == -1, "parcBitVector_NextBitSet read past end of vector (%d)", nextBit);
+
+ nextBit = parcBitVector_NextBitSet(parcBitVector, 10);
+ assertTrue(nextBit == 10, "parcBitVector_NextBitSet failed (%d)", nextBit);
+
+ nextBit = parcBitVector_NextBitSet(parcBitVector, 11);
+ assertTrue(nextBit == -1, "parcBitVector_NextBitSet should have failed (%d)", nextBit);
+
+ parcBitVector_Set(parcBitVector, 20);
+ nextBit = parcBitVector_NextBitSet(parcBitVector, 11);
+ assertTrue(nextBit == 20, "parcBitVector_NextBitSet failed (%d)", nextBit);
+ parcBitVector_Release(&parcBitVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Get)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+ assertTrue(parcBitVector_NumberOfBitsSet(parcBitVector) == 0, "parcBitVector_Create created a non-empty vector");
+
+ parcBitVector_Set(parcBitVector, 10);
+ int bitValue = parcBitVector_Get(parcBitVector, 10);
+ assertTrue(bitValue == 1, "parcBitVector_Get returned wrong value (%d)", bitValue);
+
+ bitValue = parcBitVector_Get(parcBitVector, 11);
+ assertTrue(bitValue == 0, "parcBitVector_Get returned wrong value (%d)", bitValue);
+
+ bitValue = parcBitVector_Get(parcBitVector, 100);
+ assertTrue(bitValue == -1, "parcBitVector_NextBitSet should have failed (%d)", bitValue);
+
+ parcBitVector_Release(&parcBitVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_ToString)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+
+ char *string = parcBitVector_ToString(parcBitVector);
+ assertTrue(strcmp(string, "[ ]") == 0, "parcBitVector_ToString returned unexpected representation (%s != [ ])", string);
+ parcMemory_Deallocate(&string);
+
+ parcBitVector_Set(parcBitVector, 10);
+ parcBitVector_Set(parcBitVector, 1);
+ string = parcBitVector_ToString(parcBitVector);
+ assertTrue(strcmp(string, "[ 1 10 ]") == 0, "parcBitVector_ToString returned unexpected representation (%s != [ 1 10 ])", string);
+ parcMemory_Deallocate(&string);
+
+ parcBitVector_Release(&parcBitVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Copy)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+
+ parcBitVector_Set(parcBitVector, 10);
+ PARCBitVector *copy = parcBitVector_Copy(parcBitVector);
+ assertTrue(parcBitVector_NumberOfBitsSet(copy) == 1, "parcBitVector_Copy failed to copy set bit");
+ assertTrue(parcBitVector_NextBitSet(copy, 0) == 10, "parcBitVector_Copy failed to copy correct bit");
+
+ parcBitVector_Release(&copy);
+ parcBitVector_Release(&parcBitVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Equals)
+{
+ PARCBitVector *parcBitVector = parcBitVector_Create();
+ assertTrue(parcBitVector, "parcBitVector_Create returned a NULL pointer");
+
+ parcBitVector_Set(parcBitVector, 10);
+ PARCBitVector *copy = parcBitVector_Copy(parcBitVector);
+ assertTrue(parcBitVector_Equals(parcBitVector, copy), "Duplicate vector found unequal");
+
+ parcBitVector_Set(copy, 9);
+ assertFalse(parcBitVector_Equals(parcBitVector, copy), "Unequal vector found equal");
+
+ parcBitVector_Clear(copy, 9);
+ parcBitVector_Set(copy, 29);
+ assertFalse(parcBitVector_Equals(parcBitVector, copy), "Unequal long vector found equal");
+
+ parcBitVector_Clear(copy, 29);
+ assertTrue(parcBitVector_Equals(parcBitVector, copy), "Equal long vector found unequal");
+ assertTrue(parcBitVector_Equals(copy, parcBitVector), "Equal long vector found unequal");
+
+ parcBitVector_Release(&copy);
+ parcBitVector_Release(&parcBitVector);
+}
+
+LONGBOW_TEST_CASE(Global, parcBitVector_Contains)
+{
+ PARCBitVector *supersetVector = parcBitVector_Create();
+
+ parcBitVector_Set(supersetVector, 10);
+ parcBitVector_Set(supersetVector, 11);
+
+ PARCBitVector *testVector = parcBitVector_Create();
+ parcBitVector_Set(testVector, 10);
+ assertTrue(parcBitVector_Contains(supersetVector, testVector), "Expect superset to contain testVector");
+
+ parcBitVector_Set(testVector, 12);
+ assertFalse(parcBitVector_Contains(supersetVector, testVector), "Expect superset to not contain testVector");
+
+ parcBitVector_Release(&supersetVector);
+ parcBitVector_Release(&testVector);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory 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(parc_BitVector);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Buffer.c b/libparc/parc/algol/test/test_parc_Buffer.c
new file mode 100644
index 00000000..99b3bfd6
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Buffer.c
@@ -0,0 +1,1502 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <inttypes.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Buffer.c"
+
+LONGBOW_TEST_RUNNER(parcBuffer)
+{
+ // 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(CreateDestroy);
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(GettersSetters);
+ LONGBOW_RUN_TEST_FIXTURE(CreateDestroyErrors);
+ LONGBOW_RUN_TEST_FIXTURE(Errors);
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parcBuffer)
+{
+ 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(parcBuffer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateDestroy)
+{
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Allocate);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Allocate_0);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Allocate_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Allocate_SIZE_MAX);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Wrap);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Wrap_NULL);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_Wrap_WithOffset);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcBuffer_AllocateCString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateDestroy)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateDestroy)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Allocate)
+{
+ PARCBuffer *actual = parcBuffer_Allocate(10);
+ assertTrue(parcBuffer_Position(actual) == 0, "Expected initial position to be 0.");
+ assertTrue(parcBuffer_Limit(actual) == 10, "Expected initial limit to be 10.");
+ assertTrue(_markIsDiscarded(actual), "Expected initial mark to be discarded.");
+
+ parcBuffer_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Allocate_0)
+{
+ PARCBuffer *actual = parcBuffer_Allocate(0);
+ assertTrue(parcBuffer_Position(actual) == 0, "Expected initial position to be 0.");
+ assertTrue(parcBuffer_Limit(actual) == 0, "Expected initial limit to be 10.");
+ assertTrue(_markIsDiscarded(actual), "Expected initial mark to be discarded.");
+
+ parcBuffer_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Allocate_SIZE_MAX)
+{
+ PARCBuffer *actual = parcBuffer_Allocate(SIZE_MAX);
+ assertNull(actual, "Expected parcBuffer_Allocate to return NULL");
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Wrap_NULL)
+{
+ PARCBuffer *actual = parcBuffer_Wrap(NULL, 10, 0, 10);
+ assertNull(actual, "Expected parcBuffer_Wrap to return NULL");
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Wrap)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *actual = parcBuffer_Wrap(array, 10, 0, 10);
+ assertTrue(parcBuffer_Position(actual) == 0, "Expected initial position to be 0.");
+ assertTrue(parcBuffer_Limit(actual) == sizeof(array) / sizeof(array[0]), "Expected initial limit to be 10.");
+ assertTrue(_markIsDiscarded(actual), "Expected initial mark to be discarded.");
+
+ parcBuffer_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Wrap_WithOffset)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *actual = parcBuffer_Wrap(array, 10, 3, 10);
+ assertTrue(parcBuffer_Capacity(actual) == 10, "Expected initial capacity to be 3.");
+ assertTrue(parcBuffer_Limit(actual) == 10, "Expected initial limit to be 3.");
+ assertTrue(parcBuffer_Position(actual) == 3, "Expected initial position to be 0.");
+ assertTrue(_markIsDiscarded(actual), "Expected initial mark to be discarded.");
+
+ parcBuffer_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_AllocateCString)
+{
+ PARCBuffer *buffer = parcBuffer_AllocateCString("Hello World");
+ assertNotNull(buffer, "Expected parcBuffer_AllocateCString to return non-null value");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcBuffer_Allocate_AcquireRelease)
+{
+ PARCBuffer *expected = parcBuffer_Allocate(10);
+ PARCBuffer *actual = parcBuffer_Acquire(expected);
+
+ assertTrue(expected == actual, "Expected %p, actual %p", (void *) expected, (void *) actual);
+
+ parcBuffer_Release(&expected);
+ assertTrue(expected == NULL, "Expected parcBuffer_Release to NULL the pointer.");
+ parcBuffer_Release(&actual);
+ assertTrue(actual == NULL, "Expected parcBuffer_Release to NULL the pointer.");
+}
+
+LONGBOW_TEST_FIXTURE(CreateDestroyErrors)
+{
+ LONGBOW_RUN_TEST_CASE(CreateDestroyErrors, parcBuffer_Allocate_AcquireRelease_TooMany);
+ LONGBOW_RUN_TEST_CASE(CreateDestroyErrors, parcBuffer_WrapByteArray_limit_exceeds_capacity);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateDestroyErrors)
+{
+ PARCByteArray *array = parcByteArray_Allocate(10);
+ longBowTestCase_SetClipBoardData(testCase, array);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateDestroyErrors)
+{
+ PARCByteArray *array = longBowTestCase_GetClipBoardData(testCase);
+ parcByteArray_Release(&array);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(CreateDestroyErrors, parcBuffer_Allocate_AcquireRelease_TooMany, .event = &LongBowTrapIllegalValue)
+{
+ PARCBuffer *expected = parcBuffer_Allocate(10);
+ PARCBuffer *actual = parcBuffer_Acquire(expected);
+ PARCBuffer *alias = actual;
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&actual);
+ parcBuffer_Release(&alias); // this must fail.
+}
+
+LONGBOW_TEST_CASE_EXPECTS(CreateDestroyErrors, parcBuffer_WrapByteArray_limit_exceeds_capacity, .event = &LongBowAssertEvent)
+{
+ PARCByteArray *array = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCBuffer *buffer = parcBuffer_WrapByteArray(array, 0, parcByteArray_Capacity(array) + 1);
+
+ assertNotNull(buffer, "Expected NULL");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+// LONGBOW_RUN_TEST_CASE(Global, HELPME);
+// LONGBOW_RUN_TEST_CASE(Global, HELPME2);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Array);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ArrayOffset);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Clear);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Clone);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Duplicate);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Clone_WithOffset);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Equals_ZeroLength);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Equals_Bug80);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Flip);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_GetByte);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_GetBytes);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_GetBytes_Incremental);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_HasRemaining);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_HashCode_ZeroRemaining);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Mark);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Growing);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Growing_AtLimit);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Shrinking);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Shrinking_AtLimit);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Example);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Resize_Slice);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Overlay);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Position);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutBuffer_ZeroLength_operand);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutByte);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutBytes);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutIndex);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutUint16);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_PutCString);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Remaining);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Rewind);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SetLimit);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SetLimit_TruncatePosition);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SetPosition);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_Slice);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ToString_ZeroRemaining);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SkipOver);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SkipOver_NotFound);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SkipTo_NotFound);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_SkipTo);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_FindUint8);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_FindUint8_NotFound);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_IsValid_True);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ParseNumeric_Decimal);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ParseNumeric_Hexadecimal);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_ParseHexString);
+ LONGBOW_RUN_TEST_CASE(Global, parcBuffer_CreateFromArray);
+}
+
+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) {
+ 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, HELPME)
+{
+ uint8_t decodeBytes[] = { 0x00, 0x02, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' };
+ PARCBuffer *b1 = parcBuffer_Wrap(decodeBytes, sizeof(decodeBytes), 0, sizeof(decodeBytes));
+
+ // b1 is a buffer wrapping a byte array.
+ // This will take 2 allocations: 1 for the buffer and 1 for the wrapper around the byte array.
+
+ PARCBuffer *s2 = parcBuffer_Slice(b1);
+
+ // s2 is another buffer referencing the wrapper created in the original buffer.
+ // This will increase the allocations by 1 for the buffer making it 3.
+
+ // **** DO NOT RELEASE s2
+
+ parcBuffer_Release(&b1);
+ // This releases the b1 buffer, deallocating it. The wrapper around the original byte array still has a reference to it from s2.
+ // The number of allocations is reduced by 1, making it 2 (1 for s2, and 1 for the wrapper it references)
+
+ assertTrue(parcMemory_Outstanding() == 2, "memory imbalance");
+
+ parcBuffer_Release(&s2);
+
+ assertTrue(parcMemory_Outstanding() == 0, "memory imbalance must be 0, actual %d", parcMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, HELPME2)
+{
+ uint8_t decodeBytes[] = { 0x00, 0x02, 0x00, 0x0A, 'b', 'r', 'a', 'n', 'd', 'y', 'w', 'i', 'n', 'e' };
+ PARCBuffer *b1 = parcBuffer_Allocate(sizeof(decodeBytes));
+ // This will create a buffer, a wrapper, and an allocated array of bytes to wrap.
+ // The number of allocations is 3.
+
+ parcBuffer_PutArray(b1, sizeof(decodeBytes), decodeBytes);
+ parcBuffer_Flip(b1);
+
+ PARCBuffer *s2 = parcBuffer_Slice(b1);
+ // The number of allocations is 4.
+
+ // **** DO NOT RELEASE s2
+
+ parcBuffer_Release(&b1);
+ // The number of allocations is now 3, the slice buffer, the wrapper, and the allocated array of bytes.
+
+ // This will now correctly assert
+ assertTrue(parcMemory_Outstanding() == 3, "memory imbalance");
+
+ parcBuffer_Release(&s2);
+ assertTrue(parcMemory_Outstanding() == 0, "memory imbalance");
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Equals)
+{
+ PARCBuffer *x = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+ PARCBuffer *y = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+ PARCBuffer *z = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+
+ // _Pragma("GCC diagnostic push")
+ // _Pragma("GCC diagnostic ignored \"-Wzero-length-array\"")
+ // _Pragma("GCC diagnostic ignored \"-Wgnu-empty-initializer\"")
+ struct hack {
+ uint8_t dummy;
+ uint8_t empty[];
+ };
+ struct hack h = { 0 };
+ PARCBuffer *u0 = parcBuffer_Wrap(h.empty, 0, 0, 0);
+ // _Pragma("GCC diagnostic pop")
+
+ PARCBuffer *u1 = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }, 10, 0, 10);
+ PARCBuffer *u2 = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 9, 0, 9);
+ PARCBuffer *u3 = parcBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9);
+ PARCBuffer *u4 = parcBuffer_SetPosition(parcBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 2);
+ PARCBuffer *u5 = parcBuffer_SetPosition(parcBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 9);
+ PARCBuffer *u6 = parcBuffer_SetPosition(parcBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 9);
+ PARCBuffer *u7 = parcBuffer_Wrap((uint8_t [9]) { 0 }, 0, 0, 0);
+
+ parcObjectTesting_AssertEqualsFunction(parcBuffer_Equals, x, y, z, u0, u1, u2, u3, u4, u5, u6, u7, NULL);
+
+ parcBuffer_Release(&x);
+ parcBuffer_Release(&y);
+ parcBuffer_Release(&z);
+ parcBuffer_Release(&u0);
+ parcBuffer_Release(&u1);
+ parcBuffer_Release(&u2);
+ parcBuffer_Release(&u3);
+ parcBuffer_Release(&u4);
+ parcBuffer_Release(&u5);
+ parcBuffer_Release(&u6);
+ parcBuffer_Release(&u7);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Equals_ZeroLength)
+{
+ // _Pragma("GCC diagnostic push")
+ // _Pragma("GCC diagnostic ignored \"-Wzero-length-array\"")
+ // _Pragma("GCC diagnostic ignored \"-Wgnu-empty-initializer\"")
+
+ struct hack {
+ uint8_t dummy;
+ uint8_t empty[];
+ };
+ struct hack h = { 0 };
+ PARCBuffer *x = parcBuffer_Wrap(h.empty, 0, 0, 0);
+ PARCBuffer *y = parcBuffer_Wrap(h.empty, 0, 0, 0);
+ PARCBuffer *z = parcBuffer_Wrap(h.empty, 0, 0, 0);
+
+ // _Pragma("GCC diagnostic pop")
+
+ PARCBuffer *u1 = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }, 10, 0, 10);
+ PARCBuffer *u2 = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 9, 0, 9);
+
+ parcObjectTesting_AssertEqualsFunction(parcBuffer_Equals, x, y, z, u1, u2, NULL);
+
+ parcBuffer_Release(&x);
+ parcBuffer_Release(&y);
+ parcBuffer_Release(&z);
+ parcBuffer_Release(&u1);
+ parcBuffer_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Equals_Bug80)
+{
+ PARCBuffer *x = parcBuffer_WrapCString("a");
+ PARCBuffer *y = parcBuffer_WrapCString("a");
+ PARCBuffer *z = parcBuffer_WrapCString("a");
+ PARCBuffer *u1 = parcBuffer_WrapCString("b");
+ PARCBuffer *u2 = parcBuffer_WrapCString("");
+ PARCBuffer *u3 = parcBuffer_WrapCString("ab");
+
+ parcObjectTesting_AssertEqualsFunction(parcBuffer_Equals, x, y, z, u1, u2, u3);
+
+ parcBuffer_Release(&x);
+ parcBuffer_Release(&y);
+ parcBuffer_Release(&z);
+ parcBuffer_Release(&u1);
+ parcBuffer_Release(&u2);
+ parcBuffer_Release(&u3);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Compare)
+{
+ PARCBuffer *x = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+ PARCBuffer *y = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+
+ PARCBuffer *equivalent[] = {
+ x,
+ y,
+ NULL
+ };
+ PARCBuffer *lesser[] = {
+ parcBuffer_Wrap((uint8_t [9]) { 0 }, 0, 0, 0),
+ parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8}, 10, 0, 10),
+ parcBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 5, 7, 8,}, 9, 0, 9),
+ NULL
+ };
+ PARCBuffer *greater[] = {
+ parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }, 10, 0, 10),
+ parcBuffer_Wrap((uint8_t [11]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 11, 0, 11),
+ NULL
+ };
+
+ parcObjectTesting_AssertCompareTo(parcBuffer_Compare, x, equivalent, lesser, greater);
+
+ parcBuffer_Release(&x);
+ parcBuffer_Release(&y);
+
+ for (int i = 0; lesser[i] != NULL; i++) {
+ parcBuffer_Release(&lesser[i]);
+ }
+ for (int i = 0; greater[i] != NULL; i++) {
+ parcBuffer_Release(&greater[i]);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Array)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(expected, 10, 0, 10);
+
+ PARCByteArray *array = parcBuffer_Array(buffer);
+ uint8_t *actual = parcByteArray_Array(array);
+
+ parcBuffer_Release(&buffer);
+
+ assertTrue(expected == actual,
+ "Expected %p, actual %p", (void *) expected, (void *) actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Growing)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCBuffer *buffer = parcBuffer_Allocate(12);
+ parcBuffer_PutArray(buffer, sizeof(expected), expected);
+
+ parcBuffer_SetPosition(buffer, 5);
+ parcBuffer_SetLimit(buffer, 11);
+ parcBuffer_Mark(buffer);
+
+ parcBuffer_Resize(buffer, 20);
+
+ assertTrue(buffer->position == 5, "Expected position at %d, actual %zd", 5, buffer->position);
+ assertTrue(buffer->mark == 5, "Expected mark at %d, actual %zd", 5, buffer->mark);
+ assertTrue(buffer->limit == 11, "Expected limit at %d, actual %zd", 11, buffer->limit);
+ assertTrue(parcBuffer_Capacity(buffer) == 20, "Expected capacity at %d, actual %zd", 20, parcBuffer_Capacity(buffer));
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Growing_AtLimit)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCBuffer *buffer = parcBuffer_Allocate(12);
+ parcBuffer_PutArray(buffer, sizeof(expected), expected);
+
+ parcBuffer_SetPosition(buffer, 5);
+ parcBuffer_Mark(buffer);
+
+ parcBuffer_Resize(buffer, 20);
+
+ assertTrue(buffer->position == 5, "Expected position at %d, actual %zd", 5, buffer->position);
+ assertTrue(buffer->mark == 5, "Expected mark at %d, actual %zd", 5, buffer->mark);
+ assertTrue(buffer->limit == 20, "Expected limit at %d, actual %zd", 20, buffer->limit);
+ assertTrue(parcBuffer_Capacity(buffer) == 20, "Expected capacity at %d, actual %zd", 20, parcBuffer_Capacity(buffer));
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Shrinking)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer, sizeof(expected), expected);
+
+ parcBuffer_SetPosition(buffer, 3);
+ parcBuffer_SetLimit(buffer, 4);
+ parcBuffer_Mark(buffer);
+
+ parcBuffer_Resize(buffer, 5);
+
+ assertTrue(buffer->position == 3, "Expected position at %d, actual %zd", 3, buffer->position);
+ assertTrue(buffer->mark == 3, "Expected mark to be 3");
+ assertTrue(buffer->limit == 4, "Expected limit at %d, actual %zd", 4, buffer->limit);
+ assertTrue(parcBuffer_Capacity(buffer) == 5, "Expected capacity at %d, actual %zd", 5, parcBuffer_Capacity(buffer));
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Shrinking_AtLimit)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer, sizeof(expected), expected);
+
+ parcBuffer_SetPosition(buffer, 5);
+ parcBuffer_SetLimit(buffer, 5);
+ parcBuffer_Mark(buffer);
+
+ parcBuffer_Resize(buffer, 3);
+
+ assertTrue(buffer->position == 3, "Expected position at %d, actual %zd", 3, buffer->position);
+ assertTrue(_markIsDiscarded(buffer), "Expected mark to be discarded");
+ assertTrue(buffer->limit == 3, "Expected limit at %d, actual %zd", 3, buffer->limit);
+ assertTrue(parcBuffer_Capacity(buffer) == 3, "Expected capacity at %d, actual %zd", 3, parcBuffer_Capacity(buffer));
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Example)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ parcBuffer_Resize(buffer, 4);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Resize_Slice)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ parcBuffer_SetPosition(buffer, 5);
+ PARCBuffer *slice = parcBuffer_Slice(buffer);
+
+ parcBuffer_Resize(slice, 4);
+
+ parcBuffer_Release(&buffer);
+ parcBuffer_Release(&slice);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Flip)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer, 10, expected);
+ parcBuffer_Flip(buffer);
+ assertTrue(parcBuffer_Position(buffer) == 0, "Expected position to be 0.");
+ assertTrue(parcBuffer_Limit(buffer) == 10, "Expected limit to be 10.");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Clear)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer, 10, expected);
+ parcBuffer_Clear(buffer);
+ assertTrue(parcBuffer_Position(buffer) == 0, "Expected position to be 0.");
+ assertTrue(parcBuffer_Limit(buffer) == 10, "Expected limit to be 10.");
+ assertTrue(buffer->mark >= parcBuffer_Capacity(buffer), "Expected the mark to be unset.");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_ArrayOffset)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ size_t expected = 5;
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, expected, 10);
+
+ size_t actual = parcBuffer_ArrayOffset(buffer);
+ parcBuffer_Release(&buffer);
+
+ assertTrue(0 == actual,
+ "Expected offset to be 0, actual %zd", actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Position)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 5;
+ parcBuffer_SetPosition(buffer, expected);
+
+ size_t actual = parcBuffer_Position(buffer);
+
+ assertTrue(expected == actual,
+ "Expected position to be 0, actual %zd", actual);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Overlay)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ uint8_t expected[5] = { 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ size_t position = 5;
+ parcBuffer_SetPosition(buffer, position);
+ uint8_t *actual = parcBuffer_Overlay(buffer, sizeof(array) - position);
+
+ assertTrue(memcmp(expected, actual, sizeof(expected)) == 0,
+ "Array contents should not be different.");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Clone)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *original = parcBuffer_Wrap(array, 10, 0, 10);
+
+ PARCBuffer *clone = parcBuffer_Copy(original);
+
+ assertTrue(clone != original, "Expected the clone to be a different instance.");
+
+ assertTrue(parcBuffer_Equals(original, clone), "Expected clone to be equal to the original.");
+
+ parcBuffer_Release(&original);
+ assertNull(original, "Expected the parcBuffer_Release function to NULL the pointer.");
+
+ parcBuffer_Release(&clone);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Clone_WithOffset)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *original = parcBuffer_Wrap(array, 10, 0, 10);
+ parcBuffer_SetLimit(original, 9);
+ parcBuffer_SetPosition(original, 1);
+ PARCBuffer *range = parcBuffer_Slice(original);
+
+ PARCBuffer *clone = parcBuffer_Copy(range);
+
+ assertTrue(clone != original, "Expected the clone to be a different instance.");
+
+ assertTrue(parcBuffer_Equals(range, clone), "Expected clone to be equal to the original.");
+
+ parcBuffer_Release(&clone);
+ parcBuffer_Release(&range);
+ parcBuffer_Release(&original);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_SetPosition)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 2;
+ parcBuffer_SetPosition(buffer, expected);
+ size_t actual = parcBuffer_Position(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_SetLimit)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 2;
+ parcBuffer_SetLimit(buffer, expected);
+ size_t actual = parcBuffer_Limit(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_SetLimit_TruncatePosition)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ parcBuffer_SetPosition(buffer, 5);
+ parcBuffer_Mark(buffer);
+
+ size_t expected = 2;
+ parcBuffer_SetLimit(buffer, expected);
+ size_t actual = parcBuffer_Limit(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Slice)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+ parcBuffer_GetUint8(buffer);
+
+ PARCBuffer *actual = parcBuffer_Slice(buffer);
+ assertTrue(parcBuffer_Position(actual) == 0,
+ "Expected position to be 0");
+ assertTrue(parcBuffer_Limit(actual) == parcBuffer_Remaining(buffer),
+ "Expected position to be %zd", parcBuffer_Remaining(buffer));
+ assertTrue(_markIsDiscarded(actual), "Expected the mark to be discarded.");
+
+ parcBuffer_Release(&buffer);
+ parcBuffer_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Remaining)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 2;
+ parcBuffer_SetLimit(buffer, expected);
+ size_t actual = parcBuffer_Limit(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_HasRemaining)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+ bool actual = parcBuffer_HasRemaining(buffer);
+
+ assertTrue(actual, "Expected true");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Rewind)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+ parcBuffer_SetPosition(buffer, 4);
+ size_t actual = parcBuffer_Position(buffer);
+ assertTrue(actual == 4, "Expected position to be at 4.");
+
+ parcBuffer_Rewind(buffer);
+
+ actual = parcBuffer_Position(buffer);
+ assertTrue(actual == 0, "Expected position to be at 0.");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Duplicate)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+ parcBuffer_SetPosition(buffer, 4);
+
+ PARCBuffer *buffer2 = parcBuffer_Duplicate(buffer);
+
+ assertTrue(buffer != buffer2, "Expected distinct pointers to the different buffers.");
+ assertTrue(parcBuffer_Position(buffer) == parcBuffer_Position(buffer2), "Expected equal position values.");
+ assertTrue(parcBuffer_Limit(buffer) == parcBuffer_Limit(buffer2), "Expected equal limit values.");
+ assertTrue(parcBuffer_Capacity(buffer) == parcBuffer_Capacity(buffer2), "Expected equal capacity values.");
+
+ parcBuffer_Rewind(buffer);
+ assertFalse(parcBuffer_Position(buffer) == parcBuffer_Position(buffer2), "Expected unequal position values.");
+
+ parcBuffer_Release(&buffer);
+ parcBuffer_Release(&buffer2);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_Mark)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 2;
+ parcBuffer_SetPosition(buffer, expected);
+ parcBuffer_Mark(buffer);
+ parcBuffer_SetPosition(buffer, 4);
+ parcBuffer_Reset(buffer);
+ size_t actual = parcBuffer_Position(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_PutByte)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+
+ uint8_t expectedValue = 1;
+ parcBuffer_PutUint8(buffer, expectedValue);
+
+ size_t expectedPosition = 1;
+ size_t actualPosition = parcBuffer_Position(buffer);
+
+ parcBuffer_SetPosition(buffer, 0);
+ uint8_t actualValue = parcBuffer_GetAtIndex(buffer, 0);
+ parcBuffer_Release(&buffer);
+
+ assertTrue(expectedValue == actualValue,
+ "Expected %d, actual %d", expectedValue, actualValue);
+ assertTrue(expectedPosition == actualPosition,
+ "Expected %zu, actual %zu", expectedPosition, actualPosition);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_PutCString)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+
+ char *expectedValue = "abcdefg";
+ parcBuffer_PutCString(buffer, expectedValue);
+
+ size_t expectedPosition = 8;
+ size_t actualPosition = parcBuffer_Position(buffer);
+
+ uint8_t zero = parcBuffer_GetAtIndex(buffer, 7);
+
+ assertTrue(zero == 0, "Expected zero, actual %d", zero);
+
+ assertTrue(expectedPosition == actualPosition,
+ "Expected %zu, actual %zu", expectedPosition, actualPosition);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_PutUint16)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+
+ uint16_t expectedValue = 0x1234;
+ parcBuffer_PutUint16(buffer, expectedValue);
+
+ size_t expectedPosition = 2;
+ size_t actualPosition = parcBuffer_Position(buffer);
+ assertTrue(expectedPosition == actualPosition,
+ "Expected position %zd, actual %zd", expectedPosition, actualPosition);
+
+ parcBuffer_Flip(buffer);
+ uint16_t actualValue = parcBuffer_GetUint16(buffer);
+
+ actualPosition = parcBuffer_Position(buffer);
+
+ parcBuffer_Release(&buffer);
+
+ assertTrue(expectedValue == actualValue,
+ "Expected %d, actual %d", expectedValue, actualValue);
+ assertTrue(expectedPosition == actualPosition,
+ "Expected %zu, actual %zu", expectedPosition, actualPosition);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_PutIndex)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+
+ uint8_t expected = 1;
+ parcBuffer_PutAtIndex(buffer, 0, expected);
+ uint8_t actual = parcBuffer_GetAtIndex(buffer, 0);
+
+ parcBuffer_Release(&buffer);
+
+ assertTrue(expected == actual,
+ "Expected %" PRIu8 ", actual %" PRIu8 "", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_PutBytes)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer, 10, array);
+
+ size_t expected = parcBuffer_Limit(buffer);
+ size_t actual = parcBuffer_Position(buffer);
+
+ assertTrue(expected == actual, "Expected position to be at the limit.");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_PutBuffer)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer1 = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer1, 5, array);
+
+ PARCBuffer *buffer2 = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer2, 5, &array[5]);
+ parcBuffer_Flip(buffer2);
+
+ parcBuffer_PutBuffer(buffer1, buffer2);
+
+ size_t expected = parcBuffer_Limit(buffer1);
+ size_t actual = parcBuffer_Position(buffer1);
+
+ assertTrue(expected == actual, "Expected position to be at the limit. Expected %zd, actual %zd", expected, actual);
+ assertTrue(memcmp(array, parcByteArray_Array(buffer1->array), sizeof(array)) == 0,
+ "Array content differs.");
+
+ parcBuffer_Release(&buffer1);
+ parcBuffer_Release(&buffer2);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_GetByte)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer, sizeof(expected), expected);
+ parcBuffer_Flip(buffer);
+
+ uint8_t actual = parcBuffer_GetUint8(buffer);
+
+ assertTrue(expected[0] == actual,
+ "Expected %d, actual %d", expected[0], actual);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_GetBytes)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ uint8_t actual[10];
+
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer, sizeof(expected), expected);
+ parcBuffer_Flip(buffer);
+
+ parcBuffer_GetBytes(buffer, sizeof(actual), actual);
+
+ assertTrue(memcmp(expected, actual, sizeof(actual)) == 0,
+ "Expected arrays to be equal.");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_GetBytes_Incremental)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ uint8_t actual[10];
+
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer, sizeof(expected), expected);
+ parcBuffer_Flip(buffer);
+
+ parcBuffer_GetBytes(buffer, 1, actual);
+ assertTrue(parcBuffer_Position(buffer) == 1, "Expected position to be %d\n", 1);
+ assertTrue(actual[0] == expected[0], "Expected %d, actual %d", expected[0], actual[0]);
+ parcBuffer_GetBytes(buffer, 1, actual);
+ assertTrue(parcBuffer_Position(buffer) == 2, "Expected position to be 2, actual %zd\n", parcBuffer_Position(buffer));
+ assertTrue(actual[0] == expected[1], "Expected %d, actual %d", expected[1], actual[0]);
+ parcBuffer_GetBytes(buffer, 1, actual);
+ assertTrue(parcBuffer_Position(buffer) == 3, "Expected position to be 3, actual %zd\n", parcBuffer_Position(buffer));
+ assertTrue(actual[0] == expected[2], "Expected %d, actual %d", expected[2], actual[0]);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_PutBuffer_ZeroLength_operand)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer1 = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer1, 10, array);
+
+ PARCBuffer *buffer2 = parcBuffer_Allocate(0);
+ parcBuffer_PutBuffer(buffer1, buffer2);
+
+ size_t expected = parcBuffer_Limit(buffer1);
+ size_t actual = parcBuffer_Position(buffer1);
+
+ assertTrue(expected == actual, "Expected position to be at the limit.");
+
+ parcBuffer_Release(&buffer1);
+ parcBuffer_Release(&buffer2);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_HashCode)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer1 = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer1, 10, array);
+ parcBuffer_Flip(buffer1);
+
+ PARCBuffer *buffer2 = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer2, 10, array);
+ parcBuffer_Flip(buffer2);
+
+ PARCHashCode hashX = parcBuffer_HashCode(buffer1);
+ PARCHashCode hashY = parcBuffer_HashCode(buffer2);
+
+ assertTrue(hashX == hashY, "Expected %" PRIPARCHashCode ", actual %" PRIPARCHashCode, hashX, hashY);
+
+ parcBuffer_Release(&buffer1);
+ parcBuffer_Release(&buffer2);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_HashCode_ZeroRemaining)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer1 = parcBuffer_Allocate(10);
+ parcBuffer_PutArray(buffer1, 10, array);
+
+ PARCHashCode hashX = parcBuffer_HashCode(buffer1);
+
+ assertTrue(hashX == 0, "Expected 0, actual %" PRIPARCHashCode, hashX);
+
+ parcBuffer_Release(&buffer1);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_ToString)
+{
+ uint8_t array[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 'x' };
+
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(array) - 1);
+ parcBuffer_PutArray(buffer, sizeof(array) - 1, array);
+ parcBuffer_Flip(buffer);
+
+ char *actual = parcBuffer_ToString(buffer);
+
+ assertTrue(strcmp("hello world", actual) == 0, "Expected 'hello world', actual %s", actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_ToString_ZeroRemaining)
+{
+ uint8_t array[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 'x' };
+
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(array) - 1);
+ parcBuffer_PutArray(buffer, sizeof(array) - 1, array);
+// parcBuffer_Flip(buffer);
+
+ char *actual = parcBuffer_ToString(buffer);
+
+ assertTrue(strcmp("", actual) == 0, "Expected '', actual %s", actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_SkipOver)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ uint8_t skipOverBytes[] = { 'H', 0 };
+
+ bool actual = parcBuffer_SkipOver(buffer, 1, skipOverBytes);
+
+ assertTrue(actual, "Expected parcBuffer_SkipOver to return true.");
+
+ uint8_t peekByte = parcBuffer_PeekByte(buffer);
+
+ assertTrue(peekByte == 'e', "Expected buffer to point to 'e', actual '%c'", peekByte);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_SkipOver_NotFound)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+
+ bool actual = parcBuffer_SkipOver(buffer, 8, (uint8_t *) "Helo Wrd");
+
+ assertFalse(actual, "Expected parcBuffer_SkipOver to return false.");
+
+ assertTrue(parcBuffer_Remaining(buffer) == 0,
+ "Expected buffer to have no remaining bytes. Actual %zd", parcBuffer_Remaining(buffer));
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_SkipTo)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ uint8_t skipToBytes[] = { 'l', 0 };
+
+ bool actual = parcBuffer_SkipTo(buffer, 1, skipToBytes);
+
+ assertTrue(actual, "Expected parcBuffer_SkipOver to return true.");
+
+ uint8_t peekByte = parcBuffer_PeekByte(buffer);
+
+ assertTrue(peekByte == 'l', "Expected buffer to point to 'l', actual '%c'", peekByte);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_SkipTo_NotFound)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+
+ bool actual = parcBuffer_SkipTo(buffer, 1, (uint8_t *) "x");
+
+ assertFalse(actual, "Expected parcBuffer_SkipOver to return false.");
+ assertTrue(parcBuffer_Remaining(buffer) == 0,
+ "Expected buffer to have no remaining bytes. Actual %zd", parcBuffer_Remaining(buffer));
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_FindUint8)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ size_t index = parcBuffer_FindUint8(buffer, 'e');
+ assertTrue(index == 1, "Expected index to be 1, actual %zu", index);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_FindUint8_NotFound)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ size_t index = parcBuffer_FindUint8(buffer, 'z');
+ assertTrue(index == SIZE_MAX, "Expected index to be SIZE_MAX, actual %zu", index);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_IsValid_True)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("Hello World");
+ bool actual = parcBuffer_IsValid(buffer);
+ assertTrue(actual, "Expected PARCBuffer to be valid");
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_ParseNumeric_Decimal)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("123abc");
+
+ uint64_t actual = parcBuffer_ParseNumeric(buffer);
+
+ assertTrue(actual == 123, "Expected 123, actual %" PRIu64 "", actual);
+ assertTrue(parcBuffer_Position(buffer) == 3, "Expected position to be 3, actual %zd", parcBuffer_Position(buffer));
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_ParseNumeric_Hexadecimal)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString("0x123xyz");
+
+ uint64_t actual = parcBuffer_ParseNumeric(buffer);
+
+ assertTrue(actual == 0x123, "Expected 0x123, actual %" PRIx64 "", actual);
+ assertTrue(parcBuffer_Position(buffer) == 5, "Expected position to be 5, actual %zd", parcBuffer_Position(buffer));
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_ParseHexString)
+{
+ char *expected = "00";
+ PARCBuffer *buffer = parcBuffer_ParseHexString("3030");
+ parcBuffer_Flip(buffer);
+ char *actual = parcBuffer_ToString(buffer);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+
+ parcMemory_Deallocate(&actual);
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBuffer_CreateFromArray)
+{
+ char *expected = "0123456789ABCDEF";
+ PARCBuffer *buffer = parcBuffer_CreateFromArray(expected, strlen(expected));
+
+ assertTrue(parcBuffer_Position(buffer) == 16, "Expected position to be at 15, actual %zd", parcBuffer_Position(buffer));
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_FIXTURE(GettersSetters)
+{
+ LONGBOW_RUN_TEST_CASE(GettersSetters, parcPutGetUint8);
+ LONGBOW_RUN_TEST_CASE(GettersSetters, parcPutGetUint16);
+ LONGBOW_RUN_TEST_CASE(GettersSetters, parcPutGetUint32);
+ LONGBOW_RUN_TEST_CASE(GettersSetters, parcPutGetUint64);
+ LONGBOW_RUN_TEST_CASE(GettersSetters, parcBuffer_ToHexString);
+ LONGBOW_RUN_TEST_CASE(GettersSetters, parcBuffer_ToHexString_NULLBuffer);
+ LONGBOW_RUN_TEST_CASE(GettersSetters, parcBuffer_Display);
+ LONGBOW_RUN_TEST_CASE(GettersSetters, parcBuffer_Display_NULL);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(GettersSetters)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(100);
+
+ longBowTestCase_SetClipBoardData(testCase, buffer);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(GettersSetters)
+{
+ PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase);
+ parcBuffer_Release(&buffer);
+
+ 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(GettersSetters, parcPutGetUint8)
+{
+ PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase);
+
+ uint8_t expected = 0x12;
+ parcBuffer_PutUint8(buffer, expected);
+ parcBuffer_Flip(buffer);
+ uint8_t actual = parcBuffer_GetUint8(buffer);
+
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+LONGBOW_TEST_CASE(GettersSetters, parcPutGetUint16)
+{
+ PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase);
+
+ uint16_t expected = 0x1234;
+ parcBuffer_PutUint16(buffer, expected);
+ parcBuffer_Flip(buffer);
+ uint16_t actual = parcBuffer_GetUint16(buffer);
+
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+LONGBOW_TEST_CASE(GettersSetters, parcPutGetUint32)
+{
+ PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase);
+
+ uint32_t expected = 0x12345678;
+ parcBuffer_PutUint32(buffer, expected);
+ parcBuffer_Flip(buffer);
+ uint32_t actual = parcBuffer_GetUint32(buffer);
+
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+LONGBOW_TEST_CASE(GettersSetters, parcPutGetUint64)
+{
+ PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase);
+
+ uint64_t expected = 0x1234567812345678;
+ parcBuffer_PutUint64(buffer, expected);
+ parcBuffer_Flip(buffer);
+ uint64_t actual = parcBuffer_GetUint64(buffer);
+
+ assertTrue(expected == actual, "Expected %" PRIu64 ", actual %" PRIu64 "", expected, actual);
+}
+
+LONGBOW_TEST_CASE(GettersSetters, parcBuffer_ToHexString)
+{
+ PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase);
+
+ uint64_t expected = 0x1234567812345678;
+ parcBuffer_PutUint64(buffer, expected);
+ parcBuffer_Flip(buffer);
+ char *hexString = parcBuffer_ToHexString(buffer);
+
+ assertTrue(strcmp("1234567812345678", hexString) == 0, "Expected 1234567812345678, actual %s", hexString);
+ parcMemory_Deallocate((void **) &hexString);
+}
+
+LONGBOW_TEST_CASE(GettersSetters, parcBuffer_ToHexString_NULLBuffer)
+{
+ char *hexString = parcBuffer_ToHexString(NULL);
+
+ assertTrue(strcmp("null", hexString) == 0, "Expected null, actual %s", hexString);
+ parcMemory_Deallocate((void **) &hexString);
+}
+
+LONGBOW_TEST_CASE(GettersSetters, parcBuffer_Display)
+{
+ PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase);
+
+ uint64_t expected = 0x1234567812345678;
+ parcBuffer_PutUint64(buffer, expected);
+ parcBuffer_Flip(buffer);
+ parcBuffer_Display(buffer, 0);
+}
+
+LONGBOW_TEST_CASE(GettersSetters, parcBuffer_Display_NULL)
+{
+ parcBuffer_Display(NULL, 0);
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, parcBuffer_GetByte_Underflow);
+ LONGBOW_RUN_TEST_CASE(Errors, parcBuffer_Mark_mark_exceeds_position);
+}
+
+typedef struct parc_buffer_longbow_clipboard {
+ PARCBuffer *buffer;
+} parcBuffer_LongBowClipBoard;
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ parcBuffer_LongBowClipBoard *testData = calloc(1, sizeof(parcBuffer_LongBowClipBoard));
+ testData->buffer = parcBuffer_Allocate(10);
+
+ longBowTestCase_SetClipBoardData(testCase, testData);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ parcBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ parcBuffer_Release(&testData->buffer);
+ free(testData);
+
+ 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, parcBuffer_GetByte_Underflow, .event = &LongBowTrapOutOfBounds)
+{
+ parcBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = testData->buffer;
+
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ parcBuffer_PutArray(buffer, 1, expected);
+ parcBuffer_Flip(buffer);
+
+ parcBuffer_GetUint8(buffer);
+ parcBuffer_GetUint8(buffer); // this will fail.
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcBuffer_Mark_mark_exceeds_position, .event = &LongBowAssertEvent)
+{
+ parcBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *buffer = testData->buffer;
+
+ size_t expected = 2;
+ parcBuffer_SetPosition(buffer, expected);
+ parcBuffer_Mark(buffer);
+ parcBuffer_SetPosition(buffer, 0);
+ parcBuffer_Reset(buffer);
+}
+
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, _digittoint);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ _longBowGlobal_Global_outstanding = parcMemory_Outstanding();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ size_t allocationsLeaked = parcMemory_Outstanding() - _longBowGlobal_Global_outstanding;
+
+ if (allocationsLeaked) {
+ 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(Static, _digittoint)
+{
+ char *base10 = "0123456789";
+
+ for (size_t i = 0; i < strlen(base10); i++) {
+ int expected = (int) i;
+ int actual = _digittoint(base10[i]);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+ }
+
+ char *base16 = "0123456789abcdef";
+
+ for (size_t i = 0; i < strlen(base16); i++) {
+ int expected = (int) i;
+ int actual = _digittoint(base16[i]);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+ }
+
+ base16 = "0123456789ABCDEF";
+
+ for (size_t i = 0; i < strlen(base16); i++) {
+ int expected = (int) i;
+ int actual = _digittoint(base16[i]);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+ }
+}
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcBuffer_Create);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ _longBowGlobal_Global_outstanding = parcMemory_Outstanding();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ size_t allocationsLeaked = parcMemory_Outstanding() - _longBowGlobal_Global_outstanding;
+
+ if (allocationsLeaked) {
+ 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(Performance, parcBuffer_Create)
+{
+ for (size_t i = 0; i < 1000000; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(1200);
+ parcBuffer_Release(&buffer);
+ }
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcBuffer);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_BufferChunker.c b/libparc/parc/algol/test/test_parc_BufferChunker.c
new file mode 100755
index 00000000..8f770968
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_BufferChunker.c
@@ -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.
+ */
+
+/**
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_BufferChunker.c"
+
+#include <stdio.h>
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(parc_BufferChunker)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_BufferChunker)
+{
+ 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_BufferChunker)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_CreateFromBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_Buffer);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_BufferPartial);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_BufferSmall);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_Buffer);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_BufferPartial);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_BufferSmall);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_GetChunkSize);
+}
+
+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, parc_Chunker_CreateFromBuffer)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1024);
+
+ PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+ PARCBufferChunker *copy = parcBufferChunker_Acquire(chunker);
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+ assertNotNull(copy, "Expected non-NULL copy of Chunker");
+ parcBufferChunker_Release(&copy);
+
+ parcBuffer_Release(&buffer);
+ parcBufferChunker_Release(&chunker);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_Buffer)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1024);
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+ parcBuffer_Flip(buffer);
+
+ PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcBufferChunker_ForwardIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ for (size_t i = 0; i < 32; i++) {
+ assertTrue(contents[i] == count, "Expected %zu at index %zu, got %d", count, i, contents[i]);
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 32, "Expected to iterate over 32 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcBufferChunker_Release(&chunker);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_BufferPartial)
+{
+ // Allocate something that's not divisible by the chunk size
+ PARCBuffer *buffer = parcBuffer_Allocate(1030);
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+
+ // Special 0xFF to mark the end...
+ for (int i = 0; i < 6; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+
+ parcBuffer_Flip(buffer);
+
+ PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcBufferChunker_ForwardIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ if (count < 32) {
+ for (size_t i = 0; i < 32; i++) {
+ assertTrue(contents[i] == count, "Expected %zu at index %zu, got %d", count, i, contents[i]);
+ }
+ } else {
+ for (size_t i = 0; i < 6; i++) {
+ assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]);
+ }
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 33, "Expected to iterate over 33 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcBufferChunker_Release(&chunker);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_BufferSmall)
+{
+ // Allocate something that's not divisible by the chunk size
+ PARCBuffer *buffer = parcBuffer_Allocate(16);
+
+ // Special 0xFF to mark the end...
+ for (int i = 0; i < 16; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+
+ parcBuffer_Flip(buffer);
+
+ PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcBufferChunker_ForwardIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ for (size_t i = 0; i < 16; i++) {
+ assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]);
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 1, "Expected to iterate over 1 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcBufferChunker_Release(&chunker);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_Buffer)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1024);
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+ parcBuffer_Flip(buffer);
+
+ PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcBufferChunker_ReverseIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ for (size_t i = 0; i < 32; i++) {
+ assertTrue(contents[i] == (31 - count), "Expected %zu at index %zu, got %d", (31 - count), i, contents[i]);
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 32, "Expected to iterate over 32 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcBufferChunker_Release(&chunker);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_BufferPartial)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1030);
+
+ // Special 0xFF to mark the start
+ for (int i = 0; i < 6; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+ parcBuffer_Flip(buffer);
+
+ PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcBufferChunker_ReverseIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ if (count < 32) {
+ for (size_t i = 0; i < 32; i++) {
+ assertTrue(contents[i] == (31 - count), "Expected %zu at index %zu, got %d", count, i, contents[i]);
+ }
+ } else {
+ for (size_t i = 0; i < 6; i++) {
+ assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]);
+ }
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 33, "Expected to iterate over 33 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcBufferChunker_Release(&chunker);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_BufferSmall)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(16);
+
+ // Special 0xFF to mark the start
+ for (int i = 0; i < 16; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+ parcBuffer_Flip(buffer);
+
+ PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcBufferChunker_ReverseIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ for (size_t i = 0; i < 16; i++) {
+ assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]);
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 1, "Expected to iterate over 1 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcBufferChunker_Release(&chunker);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_GetChunkSize)
+{
+ size_t expectedChunkSize = 32;
+ PARCBuffer *buffer = parcBuffer_Allocate(16);
+ PARCBufferChunker *chunker = parcBufferChunker_Create(buffer, expectedChunkSize); // each chunk is 32 bytes
+ size_t actualChunkSize = parcBufferChunker_GetChunkSize(chunker);
+
+ assertTrue(actualChunkSize == expectedChunkSize, "Expected chunk size of %zu, got %zu", expectedChunkSize, actualChunkSize);
+
+ parcBuffer_Release(&buffer);
+ parcBufferChunker_Release(&chunker);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_BufferChunker);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_BufferComposer.c b/libparc/parc/algol/test/test_parc_BufferComposer.c
new file mode 100644
index 00000000..fad9857c
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_BufferComposer.c
@@ -0,0 +1,448 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_BufferComposer.c"
+
+#include <inttypes.h>
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+typedef struct {
+ uint32_t setupAllocations;
+ PARCBufferComposer *composer;
+} TestData;
+
+static TestData*
+commonSetup()
+{
+ uint32_t outstanding = parcSafeMemory_Outstanding();
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear of %zu bytes returned NULL.", sizeof(TestData));
+ data->setupAllocations = outstanding;
+ data->composer = parcBufferComposer_Create();
+ return data;
+}
+
+static uint32_t
+commonTearDown(TestData *data)
+{
+ uint32_t setupAllocations = data->setupAllocations;
+
+ // NOTE: The `parcBufferComposer_AssertValid_IncrementSize` invalidates this object, so we must
+ // restore it to a good state in order for all memory to be released correctly.
+ (data->composer)->incrementHeuristic = sizeof(void *);
+
+ parcBufferComposer_Release(&(data->composer));
+ parcMemory_Deallocate((void **) &data);
+ return parcSafeMemory_ReportAllocation(STDOUT_FILENO) - setupAllocations;
+}
+
+LONGBOW_TEST_RUNNER(parc_BufferComposer)
+{
+ // 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(parc_BufferComposer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_BufferComposer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Allocate);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Allocate_SizeMax);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_AssertValid);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_AssertValid_NULL);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_AssertValid_IncrementSize);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutArray);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutUint16);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutUint32);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutUint64);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutUint8);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutString);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutStrings);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_Format);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutChar);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_GetBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_CreateBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_ProduceBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_PutString_Extend);
+ LONGBOW_RUN_TEST_CASE(Global, parcBufferComposer_ToString);
+}
+
+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);
+
+ uint32_t outstandingAllocations = commonTearDown(data);
+
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_Acquire)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ PARCBufferComposer *handle = parcBufferComposer_Acquire(composer);
+
+ assertNotNull(handle, "Acquired PARCBufferComposer handle should be non-NULL.");
+ assertTrue(parcBufferComposer_Equals(composer, handle), "PARCBufferComposer instances should be equal");
+
+ parcBufferComposer_Release(&handle);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_Allocate)
+{
+ size_t size = 10;
+ PARCBufferComposer *composer = parcBufferComposer_Allocate(size);
+ PARCBuffer *buffer = parcBufferComposer_GetBuffer(composer);
+
+ assertNotNull(composer, "PARCBufferComposer instance should be non-NULL.");
+ assertTrue(parcBuffer_Limit(buffer) == size,
+ "PARCBufferComposer instance's internal PARCBuffer limit must be %zu: %zu", size, parcBuffer_Limit(buffer));
+
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_Allocate_SizeMax)
+{
+ size_t size = SIZE_MAX;
+ PARCBufferComposer *composer = parcBufferComposer_Allocate(size);
+
+ assertNull(composer, "PARCBufferComposer instance should be NULL.");
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_AssertValid)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ assertNotNull(composer, "PARCBufferComposer instance should be non-NULL.");
+ parcBufferComposer_AssertValid(composer);
+
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcBufferComposer_AssertValid_NULL, .event = &LongBowTrapIllegalValue)
+{
+ parcBufferComposer_AssertValid(NULL);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcBufferComposer_AssertValid_IncrementSize, .event = &LongBowTrapIllegalValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ (data->composer)->incrementHeuristic = 0; // must be >= sizeof(void *)
+ parcBufferComposer_AssertValid(data->composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_Create)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ assertNotNull(composer, "PARCBufferComposer instance should be non-NULL.");
+
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_Equals)
+{
+ PARCBufferComposer *x = parcBufferComposer_Create();
+ PARCBufferComposer *y = parcBufferComposer_Create();
+ PARCBufferComposer *z = parcBufferComposer_Create();
+ PARCBufferComposer *u = parcBufferComposer_Allocate(10);
+
+ parcObjectTesting_AssertEqualsFunction(parcBufferComposer_Equals, x, y, z, u);
+
+ u->incrementHeuristic = 0;
+ assertFalse(parcBufferComposer_Equals(x, u), "PARCBufferComposer instances should be unequal due to size increments.");
+ assertFalse(parcBufferComposer_Equals(x, NULL), "Equals should return false since the second parameter is NULL.");
+ u->incrementHeuristic = sizeof(void *);
+
+ parcBufferComposer_Release(&x);
+ parcBufferComposer_Release(&y);
+ parcBufferComposer_Release(&z);
+ parcBufferComposer_Release(&u);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_ToString)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_Format(composer, "hello %s", "world");
+
+ char *string = parcBufferComposer_ToString(composer);
+
+ assertNotNull(string, "Expected non-NULL result from parcBufferComposer_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_GetBuffer)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ PARCBuffer *buffer = parcBufferComposer_GetBuffer(composer);
+
+ assertNotNull(composer, "PARCBufferComposer instance should be non-NULL.");
+ assertNotNull(buffer, "PARCBufferComposer instance's internal PARCBuffer should not be NULL");
+
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutArray)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ uint8_t string[6] = { 'h', 'e', 'l', 'l', 'o', '\0' };
+ parcBufferComposer_PutArray(composer, string, 6);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+
+ char expected[5] = "hello";
+ char *actual = parcBuffer_ToString(buffer);
+ assertTrue(strncmp(expected, actual, 5) == 0, "Expected strings to match. Got %s, expected %s", actual, expected);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutBuffer)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ PARCBuffer *insertee = parcBuffer_WrapCString("hello world");
+ parcBufferComposer_PutBuffer(composer, insertee);
+ parcBuffer_Release(&insertee);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+
+ char expected[11] = "hello world";
+ char *actual = parcBuffer_ToString(buffer);
+ assertTrue(strncmp(expected, actual, 11) == 0, "Expected strings to match. Got %s, expected %s", actual, expected);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutUint16)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ uint16_t val = 0x0101;
+ parcBufferComposer_PutUint16(composer, val);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ assertTrue(parcBuffer_GetUint16(buffer) == val, "Expected inserted uint16_t to be equal to %x, got %x", val, parcBuffer_GetUint16(buffer));
+
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutUint32)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ uint32_t val = 0x0101FFFF;
+ parcBufferComposer_PutUint32(composer, val);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ assertTrue(parcBuffer_GetUint32(buffer) == val, "Expected inserted uint32_t to be equal to %x, got %x", val, parcBuffer_GetUint32(buffer));
+
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutUint64)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ uint64_t val = 0x0101FFFFABCD0123;
+ parcBufferComposer_PutUint64(composer, val);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ assertTrue(parcBuffer_GetUint64(buffer) == val,
+ "Expected inserted uint64_t to be equal to %" PRIu64 ", got %" PRIu64 "", val, parcBuffer_GetUint64(buffer));
+
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutUint8)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ uint8_t byte = 0x01;
+ parcBufferComposer_PutUint8(composer, byte);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ assertTrue(parcBuffer_GetUint8(buffer) == byte, "Expected inserted byte to be equal to %x, got %x", byte, parcBuffer_GetUint8(buffer));
+
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutString)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ char string[14] = "Hello, World!";
+ parcBufferComposer_PutString(composer, string);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(buffer);
+ assertTrue(strncmp(actual, string, strlen(string)) == 0,
+ "Expected inserted string to be equal to %s, got %s", string, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutStrings)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ char string[14] = "Hello, World!";
+ parcBufferComposer_PutStrings(composer, "Hello", ", ", "World!", NULL);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(buffer);
+ assertTrue(strncmp(actual, string, strlen(string)) == 0, "Expected inserted string to be equal to %s, got %s", string, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_Format)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_Format(composer, "hello %s", "world");
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+
+ char expected[11] = "hello world";
+ char *actual = parcBuffer_ToString(buffer);
+ assertTrue(strncmp(expected, actual, 11) == 0, "Expected strings to match. Got %s, expected %s", actual, expected);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutChar)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ char byte = 'a';
+ parcBufferComposer_PutChar(composer, byte);
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+ assertTrue(parcBuffer_GetUint8(buffer) == byte, "Expected inserted char to be equal to %c, got %c", byte, parcBuffer_GetUint8(buffer));
+
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_CreateBuffer)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "hello world");
+
+ PARCBuffer *buffer = parcBufferComposer_CreateBuffer(composer);
+ parcBuffer_Flip(buffer); // flip the buffer since it was returned in write mode
+
+ char expected[11] = "hello world";
+ char *actual = parcBuffer_ToString(buffer);
+ assertTrue(strncmp(expected, actual, 11) == 0, "Expected strings to match. Got %s, expected %s", actual, expected);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_ProduceBuffer)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "hello world");
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+
+ char expected[11] = "hello world";
+ char *actual = parcBuffer_ToString(buffer);
+ assertTrue(strncmp(expected, actual, 11) == 0, "Expected strings to match. Got %s, expected %s", actual, expected);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcBufferComposer_PutString_Extend)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Allocate(4);
+ parcBufferComposer_PutString(composer, "hello world");
+
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+
+ char expected[11] = "hello world";
+ char *actual = parcBuffer_ToString(buffer);
+ assertTrue(strncmp(expected, actual, 11) == 0, "Expected strings to match. Got %s, expected %s", actual, expected);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_BufferComposer);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_ByteArray.c b/libparc/parc/algol/test/test_parc_ByteArray.c
new file mode 100755
index 00000000..971d79dd
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_ByteArray.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 test_parc_ByteArray.c
+ *
+ */
+#include "../parc_ByteArray.c"
+#include <stdio.h>
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(PARCByteArray)
+{
+ // 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(PARCByteArray)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(PARCByteArray)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Acquire_destroyoriginal);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Allocate);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Allocate_ZeroLength);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Wrap_NULL);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Wrap_ZeroLength);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Wrap);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Array);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_AddressOfIndex);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Capacity);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Copy_Allocated);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Copy_Wrapped);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_PutBytes);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_CopyOut);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_CopyInByteArray);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Get);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Put);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcByteArray_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, parcByteArray_Allocate)
+{
+ PARCByteArray *actual = parcByteArray_Allocate(10);
+
+ parcByteArray_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Allocate_ZeroLength)
+{
+ PARCByteArray *actual = parcByteArray_Allocate(0);
+ assertNotNull(actual, "parcByteArray_Allocate(0) must not return NULL.");
+ assertTrue(parcByteArray_Capacity(actual) == 0, "Expected capacity to be 0");
+
+ parcByteArray_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Wrap)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *actual = parcByteArray_Wrap(10, buffer);
+
+ parcByteArray_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Wrap_NULL)
+{
+ PARCByteArray *actual = parcByteArray_Wrap(10, NULL);
+
+ assertNull(actual, "Expected NULL return value from parcByteArray_Wrap()");
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Wrap_ZeroLength)
+{
+ PARCByteArray *actual = parcByteArray_Wrap(0, (uint8_t[1]) { 0 });
+
+ assertNotNull(actual, "Expected non-NULL return value from parcByteArray_Wrap()");
+ assertTrue(parcByteArray_Capacity(actual) == 0, "Expected capacity to be zero.");
+ parcByteArray_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Array)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *actual = parcByteArray_Wrap(10, buffer);
+ assertTrue(buffer == parcByteArray_Array(actual), "Expected the array to be the wrapped array.");
+
+ parcByteArray_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_AddressOfIndex)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *actual = parcByteArray_Wrap(10, buffer);
+ uint8_t *address = parcByteArray_AddressOfIndex(actual, 3);
+
+ assertTrue(buffer[3] == *address,
+ "Expected %d, actual %d", buffer[3], *address);
+
+ parcByteArray_Release(&actual);
+}
+
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Release)
+{
+ PARCByteArray *actual = parcByteArray_Allocate(10);
+
+ parcByteArray_Release(&actual);
+ assertNull(actual, "Expected the pointer to be NULL after parcByteArray_Release");
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Copy_Allocated)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *original = parcByteArray_Allocate(sizeof(buffer));
+ parcByteArray_PutBytes(original, 0, sizeof(buffer), buffer);
+
+ PARCByteArray *clone = parcByteArray_Copy(original);
+
+ assertTrue(original != clone, "Expected clone to be a different instance that original.");
+
+ assertTrue(parcByteArray_Equals(original, clone), "Expected the clone to be equal to the original.");
+
+ parcByteArray_Release(&original);
+ parcByteArray_Release(&clone);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Copy_Wrapped)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *original = parcByteArray_Wrap(sizeof(buffer), buffer);
+
+ PARCByteArray *clone = parcByteArray_Copy(original);
+
+ assertTrue(original != clone, "Expected clone to be a different instance that original.");
+
+ assertTrue(parcByteArray_Equals(original, clone), "Expected the clone to be equal to the original.");
+
+ parcByteArray_Release(&original);
+ parcByteArray_Release(&clone);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Compare)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *x = parcByteArray_Wrap(sizeof(buffer), buffer);
+
+ PARCByteArray **equivalents = (PARCByteArray *[]) {
+ parcByteArray_Wrap(sizeof(buffer), buffer),
+ NULL
+ };
+ PARCByteArray **lessers = (PARCByteArray *[]) {
+ parcByteArray_Wrap(sizeof(buffer) - 1, buffer),
+ parcByteArray_Wrap(sizeof(buffer) - 1, (uint8_t[]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8 }),
+ NULL
+ };
+ PARCByteArray **greaters = (PARCByteArray *[]) {
+ parcByteArray_Wrap(11, (uint8_t[]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }),
+ parcByteArray_Wrap(10, (uint8_t[]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }),
+ NULL
+ };
+ /*
+ * (a - b)
+ */
+ parcObjectTesting_AssertCompareTo(parcByteArray_Compare, x, equivalents, lessers, greaters);
+
+ parcByteArray_Release(&x);
+
+ for (int i = 0; equivalents[i] != NULL; i++) {
+ parcByteArray_Release(&equivalents[i]);
+ }
+ for (int i = 0; lessers[i] != NULL; i++) {
+ parcByteArray_Release(&lessers[i]);
+ }
+ for (int i = 0; greaters[i] != NULL; i++) {
+ parcByteArray_Release(&greaters[i]);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Equals)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *x = parcByteArray_Wrap(10, buffer);
+ PARCByteArray *y = parcByteArray_Wrap(10, buffer);
+ PARCByteArray *z = parcByteArray_Wrap(10, buffer);
+ PARCByteArray *u1 = parcByteArray_Wrap(5, buffer);
+ PARCByteArray *u2 = parcByteArray_Allocate(5);
+
+ parcObjectTesting_AssertEqualsFunction(parcByteArray_Equals, x, y, z, u1, u2, NULL);
+
+ parcByteArray_Release(&x);
+ parcByteArray_Release(&y);
+ parcByteArray_Release(&z);
+ parcByteArray_Release(&u1);
+ parcByteArray_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Capacity)
+{
+ size_t expected = 10;
+
+ PARCByteArray *actual = parcByteArray_Allocate(expected);
+ assertTrue(expected == parcByteArray_Capacity(actual), "Expected %zd, actual %zd", expected, parcByteArray_Capacity(actual));
+
+ parcByteArray_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_CopyOut)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ uint8_t actual[10];
+
+ PARCByteArray *original = parcByteArray_Wrap(10, expected);
+ parcByteArray_GetBytes(original, 0, sizeof(actual), actual);
+
+ assertTrue(memcmp(expected, actual, sizeof(actual)) == 0,
+ "Expected parcByteArray_CopyOut to copy the orginal data");
+
+ parcByteArray_Release(&original);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_PutBytes)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ uint8_t actual[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ PARCByteArray *original = parcByteArray_Wrap(10, expected);
+ parcByteArray_PutBytes(original, 0, 10, actual);
+
+ assertTrue(memcmp(expected, actual, 10) == 0,
+ "Expected parcByteArray_CopyOut to copy the orginal data");
+
+ parcByteArray_Release(&original);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_CopyInByteArray)
+{
+ uint8_t array1[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ uint8_t array2[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ uint8_t expected[10] = { 0, 1, 2, 0, 0, 0, 6, 7, 8, 9 };
+
+ PARCByteArray *a1 = parcByteArray_Wrap(10, array1);
+ PARCByteArray *a2 = parcByteArray_Wrap(10, array2);
+ parcByteArray_ArrayCopy(a1, 3, a2, 0, 3);
+
+ assertTrue(memcmp(expected, parcByteArray_Array(a1), 10) == 0,
+ "Expected parcByteArray_CopyOut to copy the orginal data");
+
+ parcByteArray_Release(&a1);
+ parcByteArray_Release(&a2);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Get)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *original = parcByteArray_Wrap(10, buffer);
+
+ for (uint8_t index = 0; index < 10; index++) {
+ uint8_t actual = parcByteArray_GetByte(original, index);
+ assertTrue(index == actual, "Expected %d, actual %d", index, actual);
+ }
+ parcByteArray_Release(&original);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Put)
+{
+ uint8_t buffer[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ PARCByteArray *original = parcByteArray_Wrap(10, buffer);
+
+ for (uint8_t index = 0; index < 10; index++) {
+ parcByteArray_PutByte(original, index, index);
+ }
+
+ for (uint8_t index = 0; index < 10; index++) {
+ uint8_t actual = parcByteArray_GetByte(original, index);
+ assertTrue(index == actual, "Expected %d, actual %d", index, actual);
+ }
+
+ parcByteArray_Release(&original);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Acquire)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *actual = parcByteArray_Wrap(10, buffer);
+ PARCByteArray *reference = parcByteArray_Acquire(actual);
+
+ assertTrue(reference == actual, "Expected the new reference to be equal to the original.");
+
+ PARCByteArray *new1 = parcByteArray_Acquire(actual);
+ assertTrue(new1 == actual, "Expected new to be the same as actual");
+
+ PARCByteArray *new2 = parcByteArray_Acquire(actual);
+ assertTrue(new2 == actual, "Expected new to be the same as actual");
+
+ parcByteArray_Release(&new1);
+ assertNull(new1, "Expected destroy to null the pointer");
+ assertNotNull(actual, "Expected destroy to NOT null the original pointer");
+
+ parcByteArray_Release(&new2);
+ assertNull(new1, "Expected destroy to null the pointer");
+ assertNotNull(actual, "Expected destroy to NOT null the original pointer");
+
+ parcByteArray_Release(&reference);
+ parcByteArray_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Acquire_destroyoriginal)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *original = parcByteArray_Wrap(10, buffer);
+
+ PARCByteArray *ref1 = parcByteArray_Acquire(original);
+ assertTrue(ref1 == original, "Expected new to be the same as original");
+
+ parcByteArray_Release(&original);
+ assertNull(original, "Expected destroy to null the pointer");
+ assertNotNull(ref1, "Expected destroy to NOT null the new reference");
+
+ parcByteArray_Release(&ref1);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_HashCode)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCByteArray *x = parcByteArray_Wrap(10, buffer);
+ PARCByteArray *y = parcByteArray_Wrap(10, buffer);
+
+ PARCHashCode hashX = parcByteArray_HashCode(x);
+ PARCHashCode hashY = parcByteArray_HashCode(y);
+
+ assertTrue(hashX == hashY,
+ "Expected %" PRIPARCHashCode ", actual %" PRIPARCHashCode, hashX, hashY);
+
+ parcByteArray_Release(&x);
+ parcByteArray_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Global, parcByteArray_Display)
+{
+ uint8_t buffer[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 };
+
+ PARCByteArray *x = parcByteArray_Wrap(sizeof(buffer), buffer);
+
+ parcByteArray_Display(x, 0);
+
+ parcByteArray_Release(&x);
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, parcByteArray_Put_overrun);
+ LONGBOW_RUN_TEST_CASE(Errors, parcByteArray_Get_overrun);
+ LONGBOW_RUN_TEST_CASE(Errors, parcByteArray_CopyIn_overrun);
+ LONGBOW_RUN_TEST_CASE(Errors, parcByteArray_CopyOut_overrun);
+}
+
+typedef struct parc_byte_array_longbow_clipboard {
+ PARCByteArray *byteArray;
+} parcByteArray_LongBowClipBoard;
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ parcByteArray_LongBowClipBoard *clipboardData = calloc(1, sizeof(parcByteArray_LongBowClipBoard));
+ clipboardData->byteArray = parcByteArray_Allocate(10);
+
+ longBowTestCase_SetClipBoardData(testCase, clipboardData);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ parcByteArray_LongBowClipBoard *clipboardData = longBowTestCase_GetClipBoardData(testCase);
+ parcByteArray_Release(&clipboardData->byteArray);
+ free(clipboardData);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcByteArray_Put_overrun, .event = &LongBowTrapOutOfBounds)
+{
+ parcByteArray_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ PARCByteArray *original = testData->byteArray;
+
+ for (uint8_t index = 0; index < 10 + 1; index++) {
+ parcByteArray_PutByte(original, index, index); // This will fail.
+ }
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcByteArray_CopyIn_overrun, .event = &LongBowTrapOutOfBounds)
+{
+ uint8_t actual[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ parcByteArray_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ PARCByteArray *original = testData->byteArray;
+ parcByteArray_GetBytes(original, 1, 10, actual); // This will fail.
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcByteArray_CopyOut_overrun, .event = &LongBowTrapOutOfBounds)
+{
+ uint8_t actual[10];
+
+ parcByteArray_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ PARCByteArray *original = testData->byteArray;
+ parcByteArray_GetBytes(original, 1, 10, actual); // This will fail.
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcByteArray_Get_overrun, .event = &LongBowTrapOutOfBounds)
+{
+ uint8_t buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ parcByteArray_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ PARCByteArray *original = testData->byteArray;
+ parcByteArray_PutBytes(original, 0, 10, buffer);
+
+ for (uint8_t index = 0; index < 10 + 1; index++) {
+ uint8_t actual = parcByteArray_GetByte(original, index); // this will fail.
+ assertTrue(index == actual, "Expected %d, actual %d", index, actual);
+ }
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARCByteArray);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Chunker.c b/libparc/parc/algol/test/test_parc_Chunker.c
new file mode 100755
index 00000000..945e6bab
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Chunker.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_Chunker.c"
+
+#include <stdio.h>
+
+#include <parc/algol/parc_Object.h>
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+typedef struct {
+ int val;
+ int dir;
+ bool atEnd;
+} _DummyChunkerState;
+
+typedef struct {
+ int start;
+ int end;
+ bool released;
+ size_t chunkSize;
+} _DummyChunker;
+
+static void *
+_InitForward(_DummyChunker *chunker)
+{
+ _DummyChunkerState *state = parcMemory_Allocate(sizeof(_DummyChunkerState));
+
+ state->val = 0;
+ state->dir = 1;
+ state->atEnd = false;
+
+ return state;
+}
+
+static bool
+_hasNext(_DummyChunker *chunker, void *voidstate)
+{
+ _DummyChunkerState *state = (_DummyChunkerState *) voidstate;
+ return !state->atEnd;
+}
+
+static void *
+_next(_DummyChunker *chunker, void *voidstate)
+{
+ _DummyChunkerState *state = (_DummyChunkerState *) voidstate;
+ state->val++;
+
+ if (state->val == chunker->end) {
+ state->atEnd = true;
+ }
+
+ return state;
+}
+
+static void *
+_get(_DummyChunker *chunker, void *voidstate)
+{
+ _DummyChunkerState *state = (_DummyChunkerState *) voidstate;
+ return &(state->val);
+}
+
+static void
+_finish(_DummyChunker *chunker, void *state)
+{
+ _DummyChunkerState *thestate = (_DummyChunkerState *) state;
+ parcMemory_Deallocate(&thestate);
+}
+
+static PARCIterator *
+_mock_ForwardIterator(const void *chunker)
+{
+ PARCIterator *iterator = parcIterator_Create((void *) chunker,
+ (void *(*)(PARCObject *))_InitForward,
+ (bool (*)(PARCObject *, void *))_hasNext,
+ (void *(*)(PARCObject *, void *))_next,
+ NULL,
+ (void *(*)(PARCObject *, void *))_get,
+ (void (*)(void *, void *))_finish,
+ NULL);
+
+ return iterator;
+}
+
+static PARCIterator *
+_mock_ReverseIterator(const void *chunker)
+{
+ PARCIterator *iterator = parcIterator_Create((void *) chunker,
+ (void *(*)(PARCObject *))_InitForward,
+ (bool (*)(PARCObject *, void *))_hasNext,
+ (void *(*)(PARCObject *, void *))_next,
+ NULL,
+ (void *(*)(PARCObject *, void *))_get,
+ (void (*)(void *, void *))_finish,
+ NULL);
+
+ return iterator;
+}
+
+static size_t
+_mock_GetChunkSize(const void *chunker)
+{
+ _DummyChunker *dummy = (_DummyChunker *) chunker;
+ return dummy->chunkSize;
+}
+
+static void
+_dummyDestroy(_DummyChunker **chunkerP)
+{
+ // pass...
+}
+
+PARCChunkerInterface *_MockChunker = &(PARCChunkerInterface) {
+ .ForwardIterator = (void *(*)(const void *))_mock_ForwardIterator,
+ .ReverseIterator = (void *(*)(const void *))_mock_ReverseIterator,
+ .GetChunkSize = (size_t (*)(const void *))_mock_GetChunkSize
+};
+
+parcObject_ExtendPARCObject(_DummyChunker, _dummyDestroy, NULL, NULL, NULL, NULL, NULL, NULL);
+parcObject_ImplementAcquire(_dummy, _DummyChunker);
+parcObject_ImplementRelease(_dummy, _DummyChunker);
+
+static _DummyChunker *
+_dummy_Create(int val)
+{
+ _DummyChunker *chunker = (_DummyChunker *) parcObject_CreateAndClearInstance(_DummyChunker);
+ chunker->start = 0;
+ chunker->end = val;
+ chunker->released = false;
+ chunker->chunkSize = val;
+ return chunker;
+}
+
+LONGBOW_TEST_RUNNER(parc_Chunker)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Chunker)
+{
+ 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_Chunker)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_GetChunkSize);
+}
+
+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, parc_Chunker_Create)
+{
+ _DummyChunker *dummy = _dummy_Create(10);
+ PARCChunker *chunker = parcChunker_Create(dummy, _MockChunker);
+ _dummy_Release(&dummy);
+
+ assertNotNull(chunker, "Expected non-NULL PARCChunker to be created from the dummy MockChunker");
+ PARCChunker *copy = parcChunker_Acquire(chunker);
+ assertNotNull(copy, "Expected non-NULL copy of the PARCChunker");
+
+ parcChunker_Release(&chunker);
+ parcChunker_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator)
+{
+ int n = 10;
+
+ _DummyChunker *dummy = _dummy_Create(n);
+ PARCChunker *chunker = parcChunker_Create(dummy, _MockChunker);
+ _dummy_Release(&dummy);
+ PARCIterator *itr = parcChunker_ForwardIterator(chunker);
+
+ int targetSum = (n * (n + 1)) / 2;
+ int sum = 0;
+ while (parcIterator_HasNext(itr)) {
+ int *val = parcIterator_Next(itr);
+ sum += *val;
+ }
+ assertTrue(targetSum == sum, "Expected the iterator to walk the chunker as needed\n");
+
+ parcIterator_Release(&itr);
+ parcChunker_Release(&chunker);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator)
+{
+ int n = 10;
+
+ _DummyChunker *dummy = _dummy_Create(n);
+ PARCChunker *chunker = parcChunker_Create(dummy, _MockChunker);
+ _dummy_Release(&dummy);
+ PARCIterator *itr = parcChunker_ReverseIterator(chunker);
+
+ int targetSum = (n * (n + 1)) / 2;
+ int sum = 0;
+ while (parcIterator_HasNext(itr)) {
+ int *val = parcIterator_Next(itr);
+ sum += *val;
+ }
+ assertTrue(targetSum == sum, "Expected the iterator to walk the chunker as needed\n");
+
+ parcIterator_Release(&itr);
+ parcChunker_Release(&chunker);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_GetChunkSize)
+{
+ int n = 10;
+
+ _DummyChunker *dummy = _dummy_Create(n);
+ PARCChunker *chunker = parcChunker_Create(dummy, _MockChunker);
+ _dummy_Release(&dummy);
+
+ size_t chunkSize = parcChunker_GetChunkSize(chunker);
+ assertTrue(chunkSize == n, "Expected the chunk size to be %d, got %zu\n", n, chunkSize);
+
+ parcChunker_Release(&chunker);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Chunker);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Clock.c b/libparc/parc/algol/test/test_parc_Clock.c
new file mode 100644
index 00000000..0adf813e
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Clock.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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Clock.c"
+#include <stdio.h>
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(parc_Clock)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Clock)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Clock)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ==========================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcClock_Wallclock);
+ LONGBOW_RUN_TEST_CASE(Global, parcClock_Wallclock_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcClock_Wallclock_GetTime);
+ LONGBOW_RUN_TEST_CASE(Global, parcClock_Wallclock_GetTimeval);
+ LONGBOW_RUN_TEST_CASE(Global, parcClock_Montonic);
+ LONGBOW_RUN_TEST_CASE(Global, parcClock_Monotonic_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcClock_Monotonic_GetTime);
+ LONGBOW_RUN_TEST_CASE(Global, parcClock_Monotonic_GetTimeval);
+
+ LONGBOW_RUN_TEST_CASE(Global, counterClock_Create);
+ LONGBOW_RUN_TEST_CASE(Global, counterClock_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, counterClock_GetTime);
+ LONGBOW_RUN_TEST_CASE(Global, counterClock_GetTime_Twice);
+ LONGBOW_RUN_TEST_CASE(Global, counterClock_GetTimeval);
+}
+
+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, parcClock_Wallclock)
+{
+ PARCClock *clock = parcClock_Wallclock();
+ assertNotNull(clock, "Got null wall clock");
+ parcClock_Release(&clock);
+}
+
+LONGBOW_TEST_CASE(Global, parcClock_Wallclock_Acquire)
+{
+ PARCClock *clock = parcClock_Wallclock();
+ PARCClock *copy = parcClock_Acquire(clock);
+ assertNotNull(copy, "Got null wall clock");
+ parcClock_Release(&copy);
+ parcClock_Release(&clock);
+}
+
+LONGBOW_TEST_CASE(Global, parcClock_Wallclock_GetTime)
+{
+ PARCClock *clock = parcClock_Wallclock();
+ uint64_t t = parcClock_GetTime(clock);
+ parcClock_Release(&clock);
+ assertTrue(t > 0, "got 0 time");
+}
+
+LONGBOW_TEST_CASE(Global, parcClock_Wallclock_GetTimeval)
+{
+ PARCClock *clock = parcClock_Wallclock();
+ struct timeval tv = { 0, 0 };
+ parcClock_GetTimeval(clock, &tv);
+ parcClock_Release(&clock);
+ assertTrue(tv.tv_sec > 0, "Got 0 seconds");
+}
+
+// -----
+
+LONGBOW_TEST_CASE(Global, parcClock_Montonic)
+{
+ PARCClock *clock = parcClock_Monotonic();
+ assertNotNull(clock, "Got null wall clock");
+ parcClock_Release(&clock);
+}
+
+LONGBOW_TEST_CASE(Global, parcClock_Monotonic_Acquire)
+{
+ PARCClock *clock = parcClock_Monotonic();
+ PARCClock *copy = parcClock_Acquire(clock);
+ assertNotNull(copy, "Got null wall clock");
+}
+
+LONGBOW_TEST_CASE(Global, parcClock_Monotonic_GetTime)
+{
+ PARCClock *clock = parcClock_Monotonic();
+ uint64_t t = parcClock_GetTime(clock);
+ parcClock_Release(&clock);
+ assertTrue(t > 0, "got 0 time");
+}
+
+LONGBOW_TEST_CASE(Global, parcClock_Monotonic_GetTimeval)
+{
+ PARCClock *clock = parcClock_Monotonic();
+ struct timeval tv = { 0, 0 };
+ parcClock_GetTimeval(clock, &tv);
+ parcClock_Release(&clock);
+ assertTrue(tv.tv_sec > 0, "Got 0 seconds");
+}
+
+// -----
+
+LONGBOW_TEST_CASE(Global, counterClock_Create)
+{
+ PARCClock *clock = parcClock_Counter();
+ assertNotNull(clock, "Got null wall clock");
+ parcClock_Release(&clock);
+}
+
+LONGBOW_TEST_CASE(Global, counterClock_Acquire)
+{
+ PARCClock *clock = parcClock_Counter();
+ PARCClock *copy = parcClock_Acquire(clock);
+ assertNotNull(copy, "Got null wall clock");
+ parcClock_Release(&copy);
+ parcClock_Release(&clock);
+}
+
+LONGBOW_TEST_CASE(Global, counterClock_GetTime)
+{
+ PARCClock *clock = parcClock_Counter();
+ uint64_t t = parcClock_GetTime(clock);
+ parcClock_Release(&clock);
+ assertTrue(t == 1, "On first call should have gotten 1");
+}
+
+LONGBOW_TEST_CASE(Global, counterClock_GetTime_Twice)
+{
+ PARCClock *clock = parcClock_Counter();
+ parcClock_GetTime(clock);
+ uint64_t t2 = parcClock_GetTime(clock);
+ parcClock_Release(&clock);
+ assertTrue(t2 == 2, "On second call should have gotten 2");
+}
+
+LONGBOW_TEST_CASE(Global, counterClock_GetTimeval)
+{
+ PARCClock *clock = parcClock_Counter();
+ struct timeval tv = { 0, 0 };
+ parcClock_GetTimeval(clock, &tv);
+ parcClock_Release(&clock);
+ assertTrue(tv.tv_usec == 1, "On first call should have gotten 1 usec");
+}
+
+
+// ==========================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Clock);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
diff --git a/libparc/parc/algol/test/test_parc_Deque.c b/libparc/parc/algol/test/test_parc_Deque.c
new file mode 100755
index 00000000..02884b4a
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Deque.c
@@ -0,0 +1,620 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_Deque.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_StdlibMemory.h>
+
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/testing/parc_MemoryTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_Deque)
+{
+ // 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(Local);
+ LONGBOW_RUN_TEST_FIXTURE(AcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+// LONGBOW_RUN_TEST_FIXTURE(Errors);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Deque)
+{
+ 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_Deque)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(AcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcDeque_CreateRelease);
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcDeque_CreateRelease_WithEquals);
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcDeque_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease)
+{
+ bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true;
+ if (leaked) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("bailing\n");
+ exit(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcDeque_CreateRelease)
+{
+ PARCDeque *deque = parcDeque_Create();
+ assertNotNull(deque, "Expected non-null result from parcDeque_Create()");
+
+ parcDeque_Release(&deque);
+ assertNull(deque, "Expected parcDeque_Release to null the pointer");
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcDeque_CreateRelease_WithEquals)
+{
+ PARCDeque *deque = parcDeque_CreateCustom(NULL, NULL);
+ assertNotNull(deque, "Expected non-null result from parcDeque_Create()");
+
+ parcDeque_Release(&deque);
+ assertNull(deque, "Expected parcDeque_Release to null the pointer");
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcDeque_AcquireRelease)
+{
+ PARCDeque *original = parcDeque_Create();
+ assertNotNull(original, "Expected non-null result from parcDeque_Create()");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcDeque_Acquire, original);
+
+ PARCDeque *reference = parcDeque_Acquire(original);
+ assertTrue(original == reference, "Expected the reference to be equal to the original.");
+
+ parcDeque_Release(&original);
+ assertNull(original, "Expected parcDeque_Release to null the pointer");
+
+ parcDeque_Append(reference, (void *) 1);
+ size_t expected = 1;
+ size_t actual = parcDeque_Size(reference);
+ assertTrue(expected == actual,
+ "Expected size %zd, actual %zd", expected, actual);
+ parcDeque_Release(&reference);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Append_One);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Append_Two);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_CreateDestroy);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_PeekFirst);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_PeekLast);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Prepend_One);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Prepend_Two);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Prepend_Three);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_IsEmpty);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_GetAtIndex);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_RemoveFirst);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_RemoveFirst_SingleElement);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_RemoveLast);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Size);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Display_NULL);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcDeque_Iterator);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true;
+ if (leaked) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Append_One)
+{
+ PARCDeque *deque = parcDeque_Create();
+ PARCDeque *actual = parcDeque_Append(deque, "element 1");
+
+ assertTrue(deque == actual, "Expected parcDeque_Append to return its argument.");
+ assertTrue(parcDeque_Size(deque) == 1, "Expected size of 1, actual %zd", parcDeque_Size(deque));
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Append_Two)
+{
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Append(deque, "element 1");
+ PARCDeque *actual = parcDeque_Append(deque, "element 2");
+
+ assertTrue(deque == actual, "Expected parcDeque_Append to return its argument.");
+ assertTrue(parcDeque_Size(deque) == 2, "Expected size of 2, actual %zd", parcDeque_Size(deque));
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_CreateDestroy)
+{
+ PARCDeque *deque = parcDeque_Create();
+ assertNotNull(deque, "Expected non-null result from parcDeque_Create()");
+
+ parcDeque_Release(&deque);
+ assertNull(deque, "Expected parcDeque_Destroy to null the pointer");
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_PeekFirst)
+{
+ char *expected = "element 2";
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Append(deque, expected);
+ parcDeque_Append(deque, "element 2");
+ parcDeque_Append(deque, "element 3");
+
+ char *actual = parcDeque_PeekFirst(deque);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual);
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_PeekLast)
+{
+ char *expected = "element 2";
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Append(deque, "element 1");
+ parcDeque_Append(deque, "element 2");
+ parcDeque_Append(deque, expected);
+
+ char *actual = parcDeque_PeekLast(deque);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual);
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Prepend_One)
+{
+ PARCDeque *deque = parcDeque_Create();
+ PARCDeque *actual = parcDeque_Prepend(deque, "element 1");
+
+ assertTrue(deque == actual, "Expected parcDeque_Append to return its argument.");
+ assertTrue(parcDeque_Size(deque) == 1, "Expected size of 1, actual %zd", parcDeque_Size(deque));
+ assertTrue(deque->head != NULL, "Expected head to be not null.");
+ assertTrue(deque->head == deque->tail, "Expected head to be equal to the tail.");
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Prepend_Two)
+{
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Prepend(deque, "element 2");
+ PARCDeque *actual = parcDeque_Prepend(deque, "element 1");
+
+ assertTrue(deque == actual, "Expected parcDeque_Prepend to return its argument.");
+ assertTrue(parcDeque_Size(deque) == 2, "Expected size of 2, actual %zd", parcDeque_Size(deque));
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Prepend_Three)
+{
+ char *expectedFirst = "expected first";
+ char *expectedLast = "expected last";
+
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Prepend(deque, expectedLast);
+ parcDeque_Prepend(deque, "element 2");
+ PARCDeque *actual = parcDeque_Prepend(deque, expectedFirst);
+
+ assertTrue(deque == actual, "Expected parcDeque_Prepend to return its argument.");
+ assertTrue(parcDeque_Size(deque) == 3, "Expected size of 3, actual %zd", parcDeque_Size(deque));
+
+ char *peek = parcDeque_PeekFirst(deque);
+ assertTrue(strcmp(expectedFirst, peek) == 0, "Expected '%s' actual '%s'", expectedFirst, peek);
+
+ peek = parcDeque_PeekLast(deque);
+ assertTrue(strcmp(expectedLast, peek) == 0, "Expected '%s' actual '%s'", expectedLast, peek);
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_RemoveFirst)
+{
+ char *expectedFirst = "expected 1st";
+ char *expectedLast = "expected last";
+
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Prepend(deque, expectedLast);
+ parcDeque_Prepend(deque, "element 2");
+ parcDeque_Prepend(deque, expectedFirst);
+
+ char *peek = parcDeque_RemoveFirst(deque);
+ assertTrue(strcmp(expectedFirst, peek) == 0, "Expected '%s' actual '%s'", expectedFirst, peek);
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_RemoveFirst_SingleElement)
+{
+ char *expectedFirst = "expected 1st";
+
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Prepend(deque, expectedFirst);
+
+ char *peek = parcDeque_RemoveFirst(deque);
+ assertTrue(strcmp(expectedFirst, peek) == 0,
+ "Expected '%s' actual '%s'", expectedFirst, peek);
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_RemoveLast)
+{
+ char *expectedFirst = "expected 1st";
+ char *expectedLast = "expected last";
+
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Prepend(deque, expectedLast);
+ parcDeque_Prepend(deque, "element 2");
+ parcDeque_Prepend(deque, expectedFirst);
+
+ char *peek = parcDeque_RemoveLast(deque);
+ assertTrue(strcmp(expectedLast, peek) == 0,
+ "Expected '%s' actual '%s'", expectedLast, peek);
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_RemoveLast_SingleElement)
+{
+ char *expectedFirst = "expected 1st";
+
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Prepend(deque, expectedFirst);
+
+ char *peek = parcDeque_RemoveLast(deque);
+ assertTrue(strcmp(expectedFirst, peek) == 0,
+ "Expected '%s' actual '%s'", expectedFirst, peek);
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Size)
+{
+ char *expectedFirst = "expected 1st";
+ char *expectedLast = "expected last";
+
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Prepend(deque, expectedLast);
+ parcDeque_Prepend(deque, "element 2");
+ parcDeque_Prepend(deque, expectedFirst);
+
+ assertTrue(parcDeque_Size(deque) == 3,
+ "Expected 3, actual %zd", parcDeque_Size(deque));
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_IsEmpty)
+{
+ char *expectedLast = "expected last";
+
+ PARCDeque *deque = parcDeque_Create();
+
+ assertTrue(parcDeque_IsEmpty(deque), "Expected true.");
+ parcDeque_Prepend(deque, expectedLast);
+ assertFalse(parcDeque_IsEmpty(deque), "Expected false.");
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_GetAtIndex)
+{
+ char *expected0 = "expected 1";
+ char *expected1 = "expected 2";
+ char *expected2 = "expected 3";
+
+ PARCDeque *deque = parcDeque_Create();
+ parcDeque_Append(deque, expected0);
+ parcDeque_Append(deque, expected1);
+ parcDeque_Append(deque, expected2);
+
+ char *actual;
+ actual = parcDeque_GetAtIndex(deque, 0);
+ assertTrue(strcmp(actual, expected0) == 0, "Expected '%s', actual '%s", expected0, actual);
+ actual = parcDeque_GetAtIndex(deque, 1);
+ assertTrue(strcmp(actual, expected1) == 0, "Expected '%s', actual '%s", expected1, actual);
+ actual = parcDeque_GetAtIndex(deque, 2);
+ assertTrue(strcmp(actual, expected2) == 0, "Expected '%s', actual '%s", expected2, actual);
+
+ parcDeque_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Equals)
+{
+ PARCDeque *x = parcDeque_Create();
+ parcDeque_Append(x, (void *) 0);
+ parcDeque_Append(x, (void *) 1);
+ parcDeque_Append(x, (void *) 2);
+ parcDeque_Append(x, (void *) 3);
+ parcDeque_Append(x, (void *) 4);
+ parcDeque_Append(x, (void *) 5);
+ PARCDeque *y = parcDeque_Create();
+ parcDeque_Append(y, (void *) 0);
+ parcDeque_Append(y, (void *) 1);
+ parcDeque_Append(y, (void *) 2);
+ parcDeque_Append(y, (void *) 3);
+ parcDeque_Append(y, (void *) 4);
+ parcDeque_Append(y, (void *) 5);
+ PARCDeque *z = parcDeque_Create();
+ parcDeque_Append(z, (void *) 0);
+ parcDeque_Append(z, (void *) 1);
+ parcDeque_Append(z, (void *) 2);
+ parcDeque_Append(z, (void *) 3);
+ parcDeque_Append(z, (void *) 4);
+ parcDeque_Append(z, (void *) 5);
+ PARCDeque *u1 = parcDeque_Create();
+ parcDeque_Append(u1, (void *) 0);
+ parcDeque_Append(u1, (void *) 1);
+ parcDeque_Append(u1, (void *) 2);
+ parcDeque_Append(u1, (void *) 3);
+ parcDeque_Append(u1, (void *) 4);
+ PARCDeque *u2 = parcDeque_Create();
+ parcDeque_Append(u2, (void *) 0);
+ parcDeque_Append(u2, (void *) 1);
+ parcDeque_Append(u2, (void *) 2);
+ parcDeque_Append(u2, (void *) 3);
+ parcDeque_Append(u2, (void *) 4);
+ parcDeque_Append(u2, (void *) 4);
+
+ parcObjectTesting_AssertEqualsFunction(parcDeque_Equals, x, y, z, u1, u2, NULL);
+
+ parcDeque_Release(&x);
+ parcDeque_Release(&y);
+ parcDeque_Release(&z);
+ parcDeque_Release(&u1);
+ parcDeque_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Copy)
+{
+ PARCDeque *x = parcDeque_Create();
+ parcDeque_Append(x, (void *) 0);
+ parcDeque_Append(x, (void *) 1);
+ parcDeque_Append(x, (void *) 2);
+ parcDeque_Append(x, (void *) 3);
+ parcDeque_Append(x, (void *) 4);
+ parcDeque_Append(x, (void *) 5);
+
+ PARCDeque *y = parcDeque_Copy(x);
+
+ assertTrue(parcDeque_Equals(x, y), "Expected the copy to be equal to the original.");
+
+ parcDeque_Release(&y);
+ parcDeque_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Display)
+{
+ PARCDeque *x = parcDeque_Create();
+ parcDeque_Append(x, (void *) 0);
+ parcDeque_Append(x, (void *) 1);
+ parcDeque_Append(x, (void *) 2);
+ parcDeque_Append(x, (void *) 3);
+ parcDeque_Append(x, (void *) 4);
+ parcDeque_Append(x, (void *) 5);
+
+ parcDeque_Display(x, 0);
+
+ parcDeque_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Display_NULL)
+{
+ parcDeque_Display(NULL, 0);
+}
+
+LONGBOW_TEST_CASE(Global, parcDeque_Iterator)
+{
+ PARCDeque *x = parcDeque_Create();
+ for (size_t i = 0; i < 100; i++) {
+ parcDeque_Append(x, (void *) i);
+ }
+
+ PARCIterator *iterator = parcDeque_Iterator(x);
+ size_t expected = 0;
+ while (parcIterator_HasNext(iterator)) {
+ size_t actual = (size_t) parcIterator_Next(iterator);
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ expected++;
+ }
+ parcIterator_Release(&iterator);
+
+ parcDeque_Release(&x);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _parcDequeNode_Create);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true;
+ if (leaked) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, _parcDequeNode_Create)
+{
+ void *element = "element";
+ struct parc_deque_node *previous = NULL;
+ struct parc_deque_node *next = NULL;
+
+ struct parc_deque_node *actual = _parcDequeNode_Create(element, previous, next);
+ _parcDequeNode_Destroy(NULL, &actual);
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, parcDeque_GetAtIndex_OutOfBounds);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ PARCDeque *deque = parcDeque_Create();
+ longBowTestCase_SetClipBoardData(testCase, deque);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ PARCDeque *deque = longBowTestCase_GetClipBoardData(testCase);
+ parcDeque_Release(&deque);
+
+ 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_EXPECTS(Errors, parcDeque_GetAtIndex_OutOfBounds, .event = &LongBowTrapOutOfBounds)
+{
+ char *expected0 = "expected 1";
+ char *expected1 = "expected 2";
+ char *expected2 = "expected 3";
+
+ PARCDeque *deque = longBowTestCase_GetClipBoardData(testCase);
+ parcDeque_Append(deque, expected0);
+ parcDeque_Append(deque, expected1);
+ parcDeque_Append(deque, expected2);
+
+ parcDeque_GetAtIndex(deque, 3);
+}
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcQueue_Append);
+ LONGBOW_RUN_TEST_CASE(Performance, parcQueue_N2);
+ LONGBOW_RUN_TEST_CASE(Performance, parcQueue_Iterator);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ parcMemory_SetInterface(&PARCStdlibMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ 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(Performance, parcQueue_Append)
+{
+ PARCDeque *x = parcDeque_Create();
+
+ for (size_t i = 0; i < 100000; i++) {
+ parcDeque_Append(x, (void *) i);
+ }
+
+ parcDeque_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Performance, parcQueue_N2)
+{
+ PARCDeque *x = parcDeque_Create();
+ for (size_t i = 0; i < 100000; i++) {
+ parcDeque_Append(x, (void *) i);
+ }
+
+ for (size_t expected = 0; expected < parcDeque_Size(x); expected++) {
+ size_t actual = (size_t) parcDeque_GetAtIndex(x, expected);
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ }
+
+ parcDeque_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Performance, parcQueue_Iterator)
+{
+ PARCDeque *x = parcDeque_Create();
+ for (size_t i = 0; i < 100000; i++) {
+ parcDeque_Append(x, (void *) i);
+ }
+
+ PARCIterator *iterator = parcDeque_Iterator(x);
+ size_t expected = 0;
+ while (parcIterator_HasNext(iterator)) {
+ size_t actual = (size_t) parcIterator_Next(iterator);
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ expected++;
+ }
+ parcIterator_Release(&iterator);
+
+ parcDeque_Release(&x);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Deque);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Dictionary.c b/libparc/parc/algol/test/test_parc_Dictionary.c
new file mode 100644
index 00000000..095f3c98
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Dictionary.c
@@ -0,0 +1,736 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include "../parc_Dictionary.c"
+
+static int *
+_keyNewInt(int key)
+{
+ int *newKey = parcMemory_Allocate(sizeof(int));
+ assertNotNull(newKey, "parcMemory_Allocate(%zu) returned NULL",
+ sizeof(int));
+ *newKey = key;
+ return newKey;
+}
+
+static int *
+_valueNewInt(int value)
+{
+ int *newValue = parcMemory_Allocate(sizeof(int));
+ assertNotNull(newValue, "parcMemory_Allocate(%zu) returned NULL", sizeof(int));
+ *newValue = value;
+ return newValue;
+}
+
+static bool
+_valueEquals(const void *value1, const void *value2)
+{
+ return *(int *) value1 == *(int *) value2;
+}
+
+static int
+_intKeyComp(const void *key1, const void *key2)
+{
+ if (*(int *) key1 < *(int *) key2) {
+ return -1;
+ }
+ if (*(int *) key1 == *(int *) key2) {
+ return 0;
+ }
+ return 1;
+}
+
+static uint32_t
+_intKeyHash(const void *key1)
+{
+ return *(int *) key1;
+}
+
+
+static void
+_keyFree(void **value)
+{
+ parcMemory_Deallocate((void **) value);
+ *value = NULL;
+}
+
+static void
+_valueFree(void **key)
+{
+ parcMemory_Deallocate((void **) key);
+ *key = NULL;
+}
+
+
+
+
+LONGBOW_TEST_RUNNER(PARC_Dictionary)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(PARC_Dictionary)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(PARC_Dictionary)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(-1);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Create);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_SetValue_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Size_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Size);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Size_AfterDelete);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Size_AfterOverwrite);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Get_EmptyTree);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Get_NonExistent);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Get_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Get);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Get_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Remove_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Remove);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Remove_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Keys);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Values);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Equals_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Equals_Not_Values);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_Dictionary_Equals_Not_Keys);
+}
+
+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, PARC_Dictionary_Create)
+{
+ PARCDictionary *dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, NULL, NULL, NULL);
+
+ parcDictionary_Destroy(&dictionary);
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_SetValue_Destroy)
+{
+ PARCDictionary *dictionary;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(1), (void *) _valueNewInt(11));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(2), (void *) _valueNewInt(12));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(3), (void *) _valueNewInt(13));
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Size_Empty)
+{
+ PARCDictionary *dictionary;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ assertTrue(0 == parcDictionary_Size(dictionary), "Wrong size of dictionary - empty, start");
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Size)
+{
+ PARCDictionary *dictionary;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(4), (void *) _valueNewInt(1004));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(3), (void *) _valueNewInt(1003));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(2), (void *) _valueNewInt(1002));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(8), (void *) _valueNewInt(1008));
+
+ assertTrue(4 == parcDictionary_Size(dictionary), "Wrong size of dictionary after add 3");
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Size_AfterDelete)
+{
+ PARCDictionary *dictionary;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(4), (void *) _valueNewInt(1004));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(3), (void *) _valueNewInt(1003));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(2), (void *) _valueNewInt(1002));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(8), (void *) _valueNewInt(1008));
+
+ int searchKey = 2;
+
+ parcDictionary_RemoveAndDestroyValue(dictionary, &searchKey);
+
+ size_t size = parcDictionary_Size(dictionary);
+
+ assertTrue(3 == size, "Wrong size of dictionary after 1 delete (%zu instead of 3)", size);
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Size_AfterOverwrite)
+{
+ PARCDictionary *dictionary;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(4), (void *) _valueNewInt(1004));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(3), (void *) _valueNewInt(1003));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(2), (void *) _valueNewInt(1002));
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(8), (void *) _valueNewInt(1008));
+
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(3), (void *) _valueNewInt(1010));
+
+ size_t size = parcDictionary_Size(dictionary);
+
+ assertTrue(4 == size, "Wrong size of dictionary after 1 delete (%zu instead of 4)", size);
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Get_EmptyTree)
+{
+ PARCDictionary *dictionary;
+
+ int key = 100;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ void *value = parcDictionary_GetValue(dictionary, &key);
+
+ assertTrue(NULL == value, "Object did not exist, must return NULL");
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Get_NonExistent)
+{
+ PARCDictionary *dictionary;
+ int key = 100;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 1; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ void *value = parcDictionary_GetValue(dictionary, &key);
+
+ assertTrue(NULL == value, "Object did not exist, must return NULL");
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Get_First)
+{
+ PARCDictionary *dictionary;
+ int key = 1;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 1; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int *value = parcDictionary_GetValue(dictionary, &key);
+
+ assertNotNull(value, "NULL value returned");
+ assertTrue(*value == (1 << 8), "Wrong object returned or not found");
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Get)
+{
+ PARCDictionary *dictionary;
+ int key = 5;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 1; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int *value = parcDictionary_GetValue(dictionary, &key);
+
+ assertNotNull(value, "NULL value returned");
+ assertTrue(*value == (5 << 8), "Wrong object returned or not found");
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Get_Last)
+{
+ PARCDictionary *dictionary;
+ int key = 9;
+
+ dictionary = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 1; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int *value = parcDictionary_GetValue(dictionary, &key);
+
+ assertNotNull(value, "NULL value returned");
+ assertTrue(*value == (9 << 8), "Wrong object returned or not found");
+
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Remove_First)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(1), (void *) _valueNewInt(1 << 8));
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int searchKey = 1;
+
+ void *data = parcDictionary_RemoveValue(dictionary1, &searchKey);
+
+ _valueFree(&data);
+
+ assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Remove)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 31; i < 40; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(30), (void *) _valueNewInt(31 << 8));
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int searchKey = 30;
+
+ void *data = parcDictionary_RemoveValue(dictionary1, &searchKey);
+
+ _valueFree(&data);
+
+ assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Remove_Last)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(100), (void *) _valueNewInt(100 << 8));
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int searchKey = 100;
+
+ void *data = parcDictionary_RemoveValue(dictionary1, &searchKey);
+
+ _valueFree(&data);
+
+ assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy_First)
+{
+ PARCDictionary *dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ PARCDictionary *dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(1), (void *) _valueNewInt(1 << 8));
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int searchKey = 1;
+
+ parcDictionary_RemoveAndDestroyValue(dictionary1, &searchKey);
+
+ assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 31; i < 40; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(30), (void *) _valueNewInt(31 << 8));
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int searchKey = 30;
+
+ parcDictionary_RemoveAndDestroyValue(dictionary1, &searchKey);
+
+ assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_RemoveAndDestroy_Last)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(100), (void *) _valueNewInt(100 << 8));
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary1, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ int searchKey = 100;
+
+ parcDictionary_RemoveAndDestroyValue(dictionary1, &searchKey);
+
+ assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Trees dont match after remove");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Keys)
+{
+ PARCDictionary *dictionary =
+ parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 0; i < 9; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ PARCArrayList *keys = parcDictionary_Keys(dictionary);
+
+ assertNotNull(keys,
+ "parcDictionary_Keys returned NULL, expected non-NULL.");
+
+ assertTrue(parcArrayList_Size(keys) == parcDictionary_Size(dictionary),
+ "Expected parcDictionary_Keys size %zu, actual %zd, ",
+ parcDictionary_Size(dictionary), parcArrayList_Size(keys));
+
+ for (int i = 0; i < 9; i++) {
+ bool found = false;
+ int *keyToFind = _keyNewInt(i);
+ for (int j = 0; j < parcArrayList_Size(keys); j++) {
+ int *keyToTest = parcArrayList_Get(keys, j);
+ if (*keyToTest == *keyToFind) {
+ found = true;
+ break;
+ }
+ }
+ assertTrue(found, "Expected to find Key %d, not found", *keyToFind);
+ parcMemory_Deallocate((void **) &keyToFind);
+ }
+ parcArrayList_Destroy(&keys);
+ parcDictionary_Destroy(&dictionary);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Values)
+{
+ PARCDictionary *dictionary =
+ parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 0; i < 9; i++) {
+ // Add some elements to the dictionary
+ parcDictionary_SetValue(dictionary, (void *) _keyNewInt(i), (void *) _valueNewInt(i << 8));
+ }
+
+ PARCArrayList *values = parcDictionary_Values(dictionary);
+
+ assertNotNull(values,
+ "parcDictionary_Values returned NULL, expected not NULL");
+
+ assertTrue(parcArrayList_Size(values) == parcDictionary_Size(dictionary),
+ "parcDictionary_Values size %zd not equal not parcDictionary_Size, %zd",
+ parcArrayList_Size(values), parcDictionary_Size(dictionary));
+
+ for (int i = 0; i < 9; i++) {
+ bool found = false;
+ int *keyToFind = _keyNewInt(i);
+ int *valueToFind = parcDictionary_GetValue(dictionary, keyToFind);
+ for (int j = 0; j < parcArrayList_Size(values); j++) {
+ int *valueToTest = parcArrayList_Get(values, j);
+ if (valueToFind == valueToTest) {
+ found = true;
+ break;
+ }
+ }
+ assertTrue(found,
+ "Expected to find value %d, not found", *valueToFind);
+ parcMemory_Deallocate((void **) &keyToFind);
+ }
+ parcArrayList_Destroy(&values);
+ parcDictionary_Destroy(&dictionary);
+}
+
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Equals_Empty)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Empty lists are not equal");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Equals_Not_Values)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ int compareSetValues = 100;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ printf("Testing dictionary equals...\n");
+
+ for (int i = 1; i < compareSetValues; i++) {
+ parcDictionary_SetValue(dictionary1,
+ (void *) _keyNewInt(i),
+ (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2,
+ (void *) _keyNewInt(compareSetValues - i),
+ (void *) _valueNewInt((compareSetValues + i) << 8));
+ }
+
+ assertFalse(parcDictionary_Equals(dictionary1, dictionary2), "Dictionaries are equal and they shouldn't be!");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Equals_Not_Keys)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ int compareSetValues = 100;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 1; i < compareSetValues; i++) {
+ parcDictionary_SetValue(dictionary1,
+ (void *) _keyNewInt(i),
+ (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2,
+ (void *) _keyNewInt(compareSetValues + i),
+ (void *) _valueNewInt((compareSetValues - i) << 8));
+ }
+
+ assertFalse(parcDictionary_Equals(dictionary1, dictionary2), "Lists are equal");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_Dictionary_Equals)
+{
+ PARCDictionary *dictionary1;
+ PARCDictionary *dictionary2;
+
+ int compareSetValues = 100;
+
+ dictionary1 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+ dictionary2 = parcDictionary_Create(_intKeyComp, _intKeyHash, _keyFree, _valueEquals, _valueFree);
+
+ for (int i = 1; i < compareSetValues; i++) {
+ parcDictionary_SetValue(dictionary1,
+ (void *) _keyNewInt(i),
+ (void *) _valueNewInt(i << 8));
+ parcDictionary_SetValue(dictionary2,
+ (void *) _keyNewInt(compareSetValues - i),
+ (void *) _valueNewInt((compareSetValues - i) << 8));
+ }
+
+ assertTrue(parcDictionary_Equals(dictionary1, dictionary2), "Dictionaries are not equal");
+
+ parcDictionary_Destroy(&dictionary1);
+ parcDictionary_Destroy(&dictionary2);
+}
+
+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(PARC_Dictionary);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Display.c b/libparc/parc/algol/test/test_parc_Display.c
new file mode 100755
index 00000000..29b9fdf2
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Display.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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_DisplayIndented.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_Display)
+{
+ // 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(parc_Display)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Display)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcDisplay_PrintLine);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcDisplay_PrintLine)
+{
+ testUnimplemented("");
+}
+
+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(parc_Display);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Environment.c b/libparc/parc/algol/test/test_parc_Environment.c
new file mode 100755
index 00000000..e4513b31
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Environment.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_Environment.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_Environment)
+{
+ // 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(parc_Environment)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Environment)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcEnvironment_GetHomeDirectory);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcEnvironment_GetHomeDirectory)
+{
+ const char *homeDirectory = parcEnvironment_GetHomeDirectory();
+ assertNotNull(homeDirectory, "Cannot get the current home directory.");
+}
+
+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(parc_Environment);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Event.c b/libparc/parc/algol/test/test_parc_Event.c
new file mode 100644
index 00000000..261cd079
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Event.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 <config.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 "../parc_Event.c"
+
+LONGBOW_TEST_RUNNER(parc_Event)
+{
+ // 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(parc_Event)
+{
+ parcEvent_EnableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Event)
+{
+ parcEvent_DisableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_Event_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Event_Start);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Event_Stop);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Event_Poll);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Event_SetPriority);
+}
+
+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 int _test_event_called = 0;
+
+static void
+_test_event(int fd, PARCEventType flags, void *data)
+{
+ _test_event_called++;
+}
+
+LONGBOW_TEST_CASE(Global, parc_Event_Create_Destroy)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEvent *parcEvent = parcEvent_Create(parcEventScheduler, fds[0], PARCEventType_Write, _test_event, NULL);
+ assertNotNull(parcEvent, "parcEvent_Create returned a null reference");
+ parcEvent_Destroy(&parcEvent);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+
+ close(fds[0]);
+ close(fds[1]);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Event_Start)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEvent *parcEvent = parcEvent_Create(parcEventScheduler, fds[0], PARCEventType_Read | PARCEventType_Write, _test_event, NULL);
+ assertNotNull(parcEvent, "parcEvent_Create returned a null reference");
+
+ _test_event_called = 0;
+ parcEvent_Start(parcEvent);
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+ assertTrue(_test_event_called == 1, "Event never called.");
+
+ parcEvent_Destroy(&parcEvent);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+static int _test_stop_event_called = 0;
+
+static void
+_test_stop_event(int fd, PARCEventType flags, void *data)
+{
+ PARCEvent **parcEvent = (PARCEvent **) data;
+ _test_stop_event_called++;
+ parcEvent_Stop(*parcEvent);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Event_Stop)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEvent *parcEvent = parcEvent_Create(parcEventScheduler, fds[0], PARCEventType_Write | PARCEventType_Persist, _test_stop_event, &parcEvent);
+ assertNotNull(parcEvent, "parcEvent_Create returned a null reference");
+
+ parcEvent_Start(parcEvent);
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+ assertTrue(_test_stop_event_called > 0, "Event never called.");
+ assertFalse(_test_stop_event_called != 1, "Event called more than once.");
+
+ parcEvent_Destroy(&parcEvent);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Event_Poll)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEvent *parcEvent = parcEvent_Create(parcEventScheduler, fds[0], PARCEventType_Write, _test_event, NULL);
+ assertNotNull(parcEvent, "parcEvent_Create returned a null reference");
+
+ result = parcEvent_Poll(parcEvent, PARCEventType_Read);
+ // should be no outstanding events
+ assertTrue(result == 0, "parcEvent_Poll returned %d\n", result);
+
+ parcEvent_Destroy(&parcEvent);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+static int _test_writeMaxPriority_event_called = 0;
+
+static void
+_test_writeMaxPriority_event(int fd, PARCEventType flags, void *data)
+{
+ PARCEvent *parcEvent = *((PARCEvent **) data);
+ parcEvent_Stop(parcEvent);
+ _test_writeMaxPriority_event_called++;
+}
+
+static int _test_writeMinPriority_event_called = 0;
+
+static void
+_test_writeMinPriority_event(int fd, PARCEventType flags, void *data)
+{
+ PARCEvent *parcEvent = *((PARCEvent **) data);
+ parcEvent_Stop(parcEvent);
+ _test_writeMinPriority_event_called++;
+}
+
+LONGBOW_TEST_CASE(Global, parc_Event_SetPriority)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ //
+ // First event to be called back disables its partner's event
+ //
+ PARCEvent *parcEventWriteMax, *parcEventWriteMin;
+ parcEventWriteMax = parcEvent_Create(parcEventScheduler, fds[0],
+ PARCEventType_Write,
+ _test_writeMaxPriority_event,
+ (void *) &parcEventWriteMin);
+ assertNotNull(parcEventWriteMax, "parcEvent_Create returned a null reference");
+ parcEventWriteMin = parcEvent_Create(parcEventScheduler, fds[1],
+ PARCEventType_Write,
+ _test_writeMinPriority_event,
+ (void *) &parcEventWriteMax);
+ assertNotNull(parcEventWriteMin, "parcEvent_Create returned a null reference");
+
+ result = parcEvent_SetPriority(parcEventWriteMin, PARCEventPriority_Minimum);
+ assertTrue(result == 0, "parcEvent_SetPriority write returned %d\n", result);
+ result = parcEvent_SetPriority(parcEventWriteMax, PARCEventPriority_Maximum);
+ assertTrue(result == 0, "parcEvent_SetPriority read returned %d\n", result);
+
+ parcEvent_Start(parcEventWriteMin);
+ parcEvent_Start(parcEventWriteMax);
+
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_NonBlocking);
+
+ assertTrue(_test_writeMaxPriority_event_called == 1, "Read event called before priority write event handled");
+ assertTrue(_test_writeMinPriority_event_called == 0, "Write event never triggered");
+
+ parcEvent_Destroy(&parcEventWriteMax);
+ parcEvent_Destroy(&parcEventWriteMin);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Event);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_EventBuffer.c b/libparc/parc/algol/test/test_parc_EventBuffer.c
new file mode 100644
index 00000000..c0b8d8c9
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_EventBuffer.c
@@ -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.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <pthread.h>
+
+#include <arpa/inet.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_EventBuffer.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_EventBuffer.c"
+
+LONGBOW_TEST_RUNNER(parc_EventBuffer)
+{
+ // 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(parc_EventBuffer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventBuffer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_GetLength_Append);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_Prepend_Pullup);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_ReadIntoBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_AppendBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_Read);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_WriteToFileDescriptor);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_ReadFromFileDescriptor);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_ReadLine_FreeLine);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventBuffer_GetQueueBuffer);
+}
+
+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, parc_EventBuffer_Create_Destroy)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create();
+ assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference");
+
+ parcEventBuffer_Destroy(&parcEventBuffer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ parcEventBuffer_DisableDebug();
+}
+
+static int _dataLength = 8192;
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_GetLength_Append)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create();
+ assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference");
+
+ char data[_dataLength];
+ parcEventBuffer_Append(parcEventBuffer, data, _dataLength);
+ assertTrue(parcEventBuffer_GetLength(parcEventBuffer) == _dataLength, "Buffer length does not match length of appended data");
+
+ parcEventBuffer_Destroy(&parcEventBuffer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+static uint8_t prependedDataValue = '1';
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_Prepend_Pullup)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create();
+ assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference");
+
+ char data[_dataLength];
+ data[0] = 2;
+ parcEventBuffer_Append(parcEventBuffer, data, _dataLength);
+ assertTrue(parcEventBuffer_GetLength(parcEventBuffer) == _dataLength, "Buffer length does not match length of appended data");
+
+ uint8_t prependedData[1];
+ prependedData[0] = prependedDataValue;
+ parcEventBuffer_Prepend(parcEventBuffer, prependedData, sizeof(uint8_t));
+ size_t bufferSize = parcEventBuffer_GetLength(parcEventBuffer);
+ assertTrue(bufferSize == (_dataLength + 1), "Buffer length does not match length plus prepended data length");
+
+ uint8_t *completeBuffer = parcEventBuffer_Pullup(parcEventBuffer, -1);
+ assertTrue(completeBuffer[0] == prependedDataValue, "Prepended data doesn't match %d != %d", completeBuffer[0], prependedDataValue);
+ assertTrue(completeBuffer[1] == 2, "Consolidated data doesn't match %d != %d", completeBuffer[1], 2);
+
+ parcEventBuffer_Destroy(&parcEventBuffer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_ReadIntoBuffer)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBufferSource = parcEventBuffer_Create();
+ assertNotNull(parcEventBufferSource, "parcEventBuffer_Create returned a null reference");
+ char sourceData[_dataLength];
+ parcEventBuffer_Append(parcEventBufferSource, sourceData, _dataLength);
+
+ PARCEventBuffer *parcEventBufferDestination = parcEventBuffer_Create();
+ assertNotNull(parcEventBufferDestination, "parcEventBuffer_Create returned a null reference");
+ char destinationData[_dataLength];
+ parcEventBuffer_Append(parcEventBufferDestination, destinationData, _dataLength);
+
+ parcEventBuffer_ReadIntoBuffer(parcEventBufferSource, parcEventBufferDestination, -1);
+ size_t bufferSize = parcEventBuffer_GetLength(parcEventBufferDestination);
+ assertTrue(bufferSize == (_dataLength * 2), "Destination buffer size doesn't match expected length");
+
+ parcEventBuffer_Destroy(&parcEventBufferSource);
+ parcEventBuffer_Destroy(&parcEventBufferDestination);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_AppendBuffer)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBufferSource = parcEventBuffer_Create();
+ assertNotNull(parcEventBufferSource, "parcEventBuffer_Create returned a null reference");
+ char sourceData[_dataLength];
+ parcEventBuffer_Append(parcEventBufferSource, sourceData, _dataLength);
+
+ PARCEventBuffer *parcEventBufferDestination = parcEventBuffer_Create();
+ assertNotNull(parcEventBufferDestination, "parcEventBuffer_Create returned a null reference");
+ char destinationData[_dataLength];
+ parcEventBuffer_Append(parcEventBufferDestination, destinationData, _dataLength);
+
+ parcEventBuffer_AppendBuffer(parcEventBufferSource, parcEventBufferDestination);
+ size_t bufferSize = parcEventBuffer_GetLength(parcEventBufferDestination);
+ assertTrue(bufferSize == (_dataLength * 2), "Destination buffer size doesn't match expected length, %zu != %d", bufferSize, _dataLength * 2);
+
+ parcEventBuffer_Destroy(&parcEventBufferSource);
+ parcEventBuffer_Destroy(&parcEventBufferDestination);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_Read)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create();
+ assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference");
+
+ char sourceData[64] = "This is a test";
+ parcEventBuffer_Append(parcEventBuffer, sourceData, 64);
+
+ char readDataBuffer[64];
+ int length = parcEventBuffer_Read(parcEventBuffer, readDataBuffer, 32);
+
+ assertTrue(strncmp(sourceData, readDataBuffer, 32) == 0,
+ "Buffer contents written do not match contents read");
+ assertTrue(length == 32, "parcEventBuffer_Read length unexpected %d != 32\n", length);
+
+ length = parcEventBuffer_Read(parcEventBuffer, NULL, 64);
+ assertTrue(length == 0, "Drain of parcEventBuffer returned %d", length);
+
+ parcEventBuffer_Destroy(&parcEventBuffer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_WriteToFileDescriptor)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create();
+ assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference");
+
+ char sourceData[100] = "This is a test";
+ parcEventBuffer_Append(parcEventBuffer, sourceData, 64);
+ size_t written = parcEventBuffer_WriteToFileDescriptor(parcEventBuffer, fds[0], 64);
+
+ assertTrue(written == 64, "Length written does not match buffer length.");
+ assertTrue(read(fds[1], sourceData, 100) == 64, "Length read does not match length written.");
+
+ parcEventBuffer_Destroy(&parcEventBuffer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_ReadFromFileDescriptor)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create();
+ assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference");
+
+ char sourceData[64] = "This is a test";
+ parcEventBuffer_Append(parcEventBuffer, sourceData, 64);
+
+ size_t written = parcEventBuffer_WriteToFileDescriptor(parcEventBuffer, fds[0], 64);
+ assertTrue(written == 64, "Length written does not match buffer length.");
+ size_t read = parcEventBuffer_ReadFromFileDescriptor(parcEventBuffer, fds[1], -1);
+
+ assertTrue(read == 64, "Length read does not match amount written.");
+
+ parcEventBuffer_Destroy(&parcEventBuffer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_ReadLine_FreeLine)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventBuffer *parcEventBuffer = parcEventBuffer_Create();
+ assertNotNull(parcEventBuffer, "parcEventBuffer_Create returned a null reference");
+
+ char sourceData[64] = "This is a test\n";
+ parcEventBuffer_Append(parcEventBuffer, sourceData, 64);
+ assertTrue(parcEventBuffer_GetLength(parcEventBuffer) == 64, "parcEventBuffer has wrong length %zu.", parcEventBuffer_GetLength(parcEventBuffer));
+
+ size_t bytesRead;
+ char *lineRead = parcEventBuffer_ReadLine(parcEventBuffer, &bytesRead);
+ // read up to newline and terminate, so we read the newline but don't return it in the result
+ assertTrue(parcEventBuffer_GetLength(parcEventBuffer) == (64 - (bytesRead + 1)),
+ "parcEventBuffer has wrong length %zu != %zu.",
+ (64 - (bytesRead + 1)), parcEventBuffer_GetLength(parcEventBuffer));
+ assertTrue(strncmp(sourceData, lineRead, bytesRead) == 0, "Line read doesn't match %s != %s", sourceData, lineRead);
+ assertTrue((strlen(sourceData) - strlen(lineRead)) == 1, "Line length doesn't match %zu != %zu", strlen(sourceData), strlen(lineRead));
+
+ parcEventBuffer_FreeLine(parcEventBuffer, &lineRead);
+
+ parcEventBuffer_Destroy(&parcEventBuffer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventBuffer_GetQueueBuffer)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ parcEventBuffer_EnableDebug(parcEventScheduler_GetLogger(parcEventScheduler));
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, fds[0], 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ PARCEventBuffer *parcEventBuffer_Output = parcEventBuffer_GetQueueBufferOutput(parcEventQueue);
+ assertNotNull(parcEventBuffer_Output, "Received null output buffer from queue");
+
+ PARCEventBuffer *parcEventBuffer_Input = parcEventBuffer_GetQueueBufferInput(parcEventQueue);
+ assertNotNull(parcEventBuffer_Input, "Received null input buffer from queue");
+
+ parcEventBuffer_Destroy(&parcEventBuffer_Output);
+ parcEventBuffer_Destroy(&parcEventBuffer_Input);
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventBuffer);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_EventQueue.c b/libparc/parc/algol/test/test_parc_EventQueue.c
new file mode 100644
index 00000000..862cb61d
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_EventQueue.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <arpa/inet.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_EventQueue.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_EventQueue.c"
+
+LONGBOW_TEST_RUNNER(parc_EventQueue)
+{
+ // 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(parc_EventQueue)
+{
+ parcEventQueue_EnableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventQueue)
+{
+ parcEventQueue_DisableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_SetFileDescriptor_GetFileDecriptor);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Get_Enable_Disable);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_SetCallbacks);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Flush);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Finished);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_SetWatermark);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_ReadWrite);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_SetPriority);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Printf);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_GetEvBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_ConnectSocket);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_Create_Destroy_Pair);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventQueue_GetUpDownQueue);
+}
+
+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, parc_EventQueue_Create_Destroy)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ assertNull(parcEventQueue, "parcEventQueue_Destroy did not clear reference");
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ assertNull(parcEventScheduler, "parcEventScheduler_Destroy did not clear reference");
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_Get_Enable_Disable)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ PARCEventType defaultEvents = parcEventQueue_GetEnabled(parcEventQueue);
+
+ parcEventQueue_Enable(parcEventQueue, PARCEventType_Read);
+ PARCEventType newEvents = parcEventQueue_GetEnabled(parcEventQueue);
+ assertTrue(newEvents == (defaultEvents | PARCEventType_Read),
+ "parcEventQueue_GetEnabled returned incorrect event set 0x%x != 0x%x",
+ newEvents, defaultEvents | PARCEventType_Read);
+
+ parcEventQueue_Disable(parcEventQueue, PARCEventType_Read);
+
+ newEvents = parcEventQueue_GetEnabled(parcEventQueue);
+ assertTrue(defaultEvents == newEvents, "parcEventQueue_GetEnabled returned incorrect event set 0x%x != 0x%x", newEvents, defaultEvents);
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_SetFileDescriptor_GetFileDecriptor)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned null");
+
+ result = parcEventQueue_SetFileDescriptor(parcEventQueue, fds[0]);
+ assertTrue(result == 0, " parcEventQueue_SetFileDescriptor call failed");
+
+ result = parcEventQueue_GetFileDescriptor(parcEventQueue);
+ assertTrue(result == fds[0], "parcEventQueue_GetFileDescriptor failed");
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_Create_Destroy_Pair)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned null");
+
+ PARCEventQueuePair *parcEventQueuePair = parcEventQueue_CreateConnectedPair(parcEventScheduler);
+ assertNotNull(parcEventQueuePair, "parcEventQueue_CreateConnectedPair returned a null pair");
+
+ parcEventQueue_DestroyConnectedPair(&parcEventQueuePair);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_GetUpDownQueue)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+
+ PARCEventQueuePair *parcEventQueuePair = parcEventQueue_CreateConnectedPair(parcEventScheduler);
+
+ assertNotNull(parcEventQueue_GetConnectedUpQueue(parcEventQueuePair), "parcEventQueue_GetUpQueue returned null");
+ assertNotNull(parcEventQueue_GetConnectedDownQueue(parcEventQueuePair), "parcEventQueue_GetDownQueue returned null");
+
+ parcEventQueue_DestroyConnectedPair(&parcEventQueuePair);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+static int _queue_callback_count = 0;
+
+static void
+_queue_callback(PARCEventQueue *event, PARCEventType type, void *data)
+{
+ _queue_callback_count++;
+}
+
+static int _queue_event_callback_count = 0;
+
+static void
+_queue_event_callback(PARCEventQueue *event, PARCEventQueueEventType type, void *data)
+{
+ _queue_event_callback_count++;
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_SetCallbacks)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ parcEventQueue_SetCallbacks(parcEventQueue,
+ _queue_callback,
+ _queue_callback,
+ _queue_event_callback,
+ NULL);
+
+ _parc_queue_read_callback(NULL, parcEventQueue);
+ assertTrue(_queue_callback_count == 1, "Callback count expected 1 got %d", _queue_callback_count);
+
+ _parc_queue_write_callback(NULL, parcEventQueue);
+ assertTrue(_queue_callback_count == 2, "Callback count expected 2 got %d", _queue_callback_count);
+
+ _parc_queue_event_callback(NULL, PARCEventQueueEventType_EOF, parcEventQueue);
+ assertTrue(_queue_event_callback_count == 1, "Callback event count expected 1 got %d", _queue_event_callback_count);
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_Flush)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ int result = parcEventQueue_Flush(parcEventQueue, PARCEventType_Read);
+ assertTrue(result == 0, "parcEventQueue_Flush failed with %d", result);
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_Finished)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ int result = parcEventQueue_Finished(parcEventQueue, PARCEventType_Read);
+ assertTrue(result == 0, "parcEventQueue_Finished failed with %d", result);
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_SetWatermark)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ parcEventQueue_SetWatermark(parcEventQueue, PARCEventType_Read, 0, 0);
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_ReadWrite)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ char *data = "Hello World\n";
+ int length = strlen(data);
+ int result = parcEventQueue_Write(parcEventQueue, data, length);
+ assertTrue(result == 0, "parcEventQueue_Write failed.");
+
+ char buffer[64];
+ result = parcEventQueue_Read(parcEventQueue, buffer, 64);
+ assertTrue(result == 0, "parcEventQueue_Read failed.");
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+static int _test_writeMaxPriority_event_called = 0;
+static void
+_test_writeMaxPriority_callback(PARCEventQueue *parcEventQueue, PARCEventType event, void *data)
+{
+ PARCEventQueue *parcEventQueuePartner = *((PARCEventQueue **) data);
+ parcEventQueue_Disable(parcEventQueuePartner, event);
+ _test_writeMaxPriority_event_called++;
+}
+
+static int _test_writeMinPriority_event_called = 0;
+static void
+_test_writeMinPriority_callback(PARCEventQueue *parcEventQueue, PARCEventType event, void *data)
+{
+ PARCEventQueue *parcEventQueuePartner = *((PARCEventQueue **) data);
+ parcEventQueue_Disable(parcEventQueuePartner, event);
+ _test_writeMinPriority_event_called++;
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_SetPriority)
+{
+ int fds[2];
+ int result = socketpair(AF_LOCAL, SOCK_DGRAM, 0, fds);
+ assertFalse(result, "Socketpair creation failed.\n");
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ //
+ // First queue to be called back disables its partner's queue
+ //
+ PARCEventQueue *parcEventQueueMin, *parcEventQueueMax;
+ parcEventQueueMin = parcEventQueue_Create(parcEventScheduler, fds[0], PARCEventQueueOption_CloseOnFree);
+ assertNotNull(parcEventQueueMin, "parcEventQueue_Create returned a null reference");
+ parcEventQueue_SetCallbacks(parcEventQueueMin, NULL, _test_writeMinPriority_callback, NULL, (void *) &parcEventQueueMax);
+
+ parcEventQueueMax = parcEventQueue_Create(parcEventScheduler, fds[0], PARCEventQueueOption_CloseOnFree);
+ assertNotNull(parcEventQueueMax, "parcEventQueue_Create returned a null reference");
+ parcEventQueue_SetCallbacks(parcEventQueueMax, NULL, _test_writeMaxPriority_callback, NULL, (void *) &parcEventQueueMin);
+
+ result = parcEventQueue_SetPriority(parcEventQueueMin, PARCEventPriority_Minimum);
+ assertTrue(result == 0, "parcEventQueue_SetPriority Minimum priority failed.");
+ result = parcEventQueue_SetPriority(parcEventQueueMax, PARCEventPriority_Maximum);
+ assertTrue(result == 0, "parcEventQueue_SetPriority Maximum priority failed.");
+
+ parcEventQueue_Enable(parcEventQueueMin, PARCEventType_Write);
+ parcEventQueue_Enable(parcEventQueueMax, PARCEventType_Write);
+
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_NonBlocking);
+
+ assertTrue(_test_writeMaxPriority_event_called == 1, "Read event called before priority write event handled");
+ assertTrue(_test_writeMinPriority_event_called == 0, "Write event never triggered");
+
+ parcEventQueue_Destroy(&parcEventQueueMin);
+ parcEventQueue_Destroy(&parcEventQueueMax);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ close(fds[0]);
+ close(fds[1]);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_Printf)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ int result = parcEventQueue_Printf(parcEventQueue, "%s %s\n", "Hello", "World");
+ assertTrue(result == 12, "parcEventQueue_Printf didn't write expected length %d != %d", result, 12);
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_GetEvBuffer)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, 0, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ struct evbuffer *result = internal_parcEventQueue_GetEvInputBuffer(parcEventQueue);
+ assertTrue(result != NULL, "parcEventQueue_GetEvInputBuffer failed.");
+
+ result = internal_parcEventQueue_GetEvOutputBuffer(parcEventQueue);
+ assertTrue(result != NULL, "parcEventQueue_GetEvOutputBuffer failed.");
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventQueue_ConnectSocket)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventQueue *parcEventQueue = parcEventQueue_Create(parcEventScheduler, -1, 0);
+ assertNotNull(parcEventQueue, "parcEventQueue_Create returned a null reference");
+
+ struct sockaddr_in address;
+ int addressLength = sizeof(address);
+ memset(&address, 0, addressLength);
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
+ address.sin_port = htons(8080); /* Port 8080 */
+
+ int result = parcEventQueue_ConnectSocket(parcEventQueue, (struct sockaddr *) &address, addressLength);
+ assertTrue(result == 0, "parcEventQueue_ConnectSocket returned %d", result);
+
+ parcEventQueue_Destroy(&parcEventQueue);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventQueue);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_EventScheduler.c b/libparc/parc/algol/test/test_parc_EventScheduler.c
new file mode 100755
index 00000000..8195bd2e
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_EventScheduler.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+
+#include <pthread.h>
+
+#include <LongBow/unit-test.h>
+
+#include "../internal_parc_Event.h"
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_EventTimer.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_EventScheduler.c"
+
+LONGBOW_TEST_RUNNER(parc_EventScheduler)
+{
+ // 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(parc_EventScheduler)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventScheduler)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Run);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Dispatch);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Stop);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Abort);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_Memory);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_GetEvBase);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventScheduler_GetLogger);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcEventScheduler_EnableDebug();
+ 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;
+ }
+
+ parcEventScheduler_DisableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventScheduler_Create_Destroy)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ parcEventScheduler_Destroy(&parcEventScheduler);
+ assertNull(parcEventScheduler, "parcEventScheduler_Destroy failed to null reference");
+}
+
+static void
+_event_callback(int fd, PARCEventType flags, void *data)
+{
+ (*(unsigned *) data)++;
+}
+
+static int _callback_event_called = 0;
+
+LONGBOW_TEST_CASE(Global, parc_EventScheduler_Run)
+{
+ _callback_event_called = 0;
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEventTimer *parcEvent = parcEventTimer_Create(parcEventScheduler, 0, _event_callback, (void *) &_callback_event_called);
+ assertNotNull(parcEvent, "parcEventTimer_Create returned a null reference");
+
+ struct timeval fs = { 0, 1 };
+ parcEventTimer_Start(parcEvent, &fs);
+
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+ assertTrue(_callback_event_called == 1, "Timer event never called back");
+
+ parcEventTimer_Destroy(&parcEvent);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventScheduler_Dispatch)
+{
+ _callback_event_called = 0;
+
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEventTimer *parcEvent = parcEventTimer_Create(parcEventScheduler, 0, _event_callback, (void *) &_callback_event_called);
+ assertNotNull(parcEvent, "parcEventTimer_Create returned a null reference");
+
+ struct timeval fs = { 0, 1 };
+ parcEventTimer_Start(parcEvent, &fs);
+
+ // This will block until the event is processed
+ parcEventScheduler_DispatchBlocking(parcEventScheduler);
+ assertTrue(_callback_event_called == 1, "Timer event never called back");
+
+ // Start the timer
+ struct timeval longerfs = { 1, 0 }; // 1s
+ parcEventTimer_Start(parcEvent, &longerfs);
+ parcEventScheduler_DispatchNonBlocking(parcEventScheduler);
+ assertTrue(_callback_event_called == 1, "Timer event called again prematurely");
+ usleep(2000000); // 2s
+ parcEventScheduler_DispatchNonBlocking(parcEventScheduler);
+ assertTrue(_callback_event_called == 2, "Timer event never called back");
+
+ parcEventTimer_Destroy(&parcEvent);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+static void
+_stop_callback(int fd, PARCEventType flags, void *data)
+{
+ PARCEventScheduler *parcEventScheduler = (PARCEventScheduler *) data;
+ struct timeval fs = { 0, 0 };
+ parcEventScheduler_Stop(parcEventScheduler, &fs);
+ _callback_event_called++;
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventScheduler_Stop)
+{
+ _callback_event_called = 0;
+
+ // Create a new scheduler
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ // Create a persistent event which will repeat until stopped
+ PARCEventTimer *parcEvent = parcEventTimer_Create(parcEventScheduler, PARCEventType_Persist, _stop_callback, parcEventScheduler);
+ assertNotNull(parcEvent, "parcEventTimer_Create returned a null reference");
+
+ struct timeval fs = { 1, 0 };
+ parcEventTimer_Start(parcEvent, &fs);
+
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+ assertTrue(_callback_event_called == 1, "Timer event never called back");
+
+ parcEventTimer_Destroy(&parcEvent);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+static void
+_abort_callback(int fd, PARCEventType flags, void *data)
+{
+ PARCEventScheduler *parcEventScheduler = (PARCEventScheduler *) data;
+ parcEventScheduler_Abort(parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventScheduler_Abort)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEventTimer *parcEvent = parcEventTimer_Create(parcEventScheduler, PARCEventType_Persist, _abort_callback, parcEventScheduler);
+ assertNotNull(parcEvent, "parcEventTimer_Create returned a null reference");
+
+ struct timeval fs = { 1, 0 };
+ parcEventTimer_Start(parcEvent, &fs);
+
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+
+ parcEventTimer_Destroy(&parcEvent);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+static void
+_test_memory_event(int fd, short flags, void *data)
+{
+}
+
+/**
+ * Ensure that the scheduler is using parc memory inside libevent
+ */
+LONGBOW_TEST_CASE(Global, parc_EventScheduler_Memory)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ size_t baseline = parcMemory_Outstanding();
+
+ struct event *testEvent = event_new(parcEventScheduler_GetEvBase(parcEventScheduler), -1, 0, _test_memory_event, NULL);
+
+ assertTrue(parcMemory_Outstanding() > baseline,
+ "event_new() did not increase parcMemory_Outstanding: baseline %zu now %u",
+ baseline,
+ parcMemory_Outstanding());
+
+ event_free(testEvent);
+
+ assertTrue(parcMemory_Outstanding() == baseline,
+ "event_free() did reduce to baseline: baseline %zu now %u",
+ baseline,
+ parcMemory_Outstanding());
+
+ parcEventScheduler_Destroy(&parcEventScheduler);
+
+ assertTrue(parcSafeMemory_ReportAllocation(STDOUT_FILENO) == 0, "Memory imbalance on create/destroy: %u", parcMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventScheduler_GetEvBase)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ assertNotNull(parcEventScheduler_GetEvBase(parcEventScheduler), "Expected a non-null EV pointer.");
+
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventScheduler_GetLogger)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ assertNotNull(parcEventScheduler_GetLogger(parcEventScheduler), "Expected a non-null logger.");
+
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventScheduler);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_EventSignal.c b/libparc/parc/algol/test/test_parc_EventSignal.c
new file mode 100644
index 00000000..fcb86333
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_EventSignal.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 <pthread.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_EventSignal.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_EventSignal.c"
+
+LONGBOW_TEST_RUNNER(parc_EventSignal)
+{
+ // 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(parc_EventSignal)
+{
+ parcEventSignal_EnableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventSignal)
+{
+ parcEventSignal_DisableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventSignal_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventSignal_Start_Stop);
+}
+
+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 int _empty_event_called = 0;
+
+static void
+_empty_event(int fd, PARCEventType flags, void *data)
+{
+ _empty_event_called++;
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventSignal_Create_Destroy)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventSignal *parcEventSignal = parcEventSignal_Create(parcEventScheduler, SIGUSR1, PARCEventType_Signal | PARCEventType_Persist, _empty_event, NULL);
+ assertNotNull(parcEventSignal, "parcEventSignal_Create returned a null reference");
+
+ _parc_event_signal_callback(0, 0, (void *) parcEventSignal);
+ assertTrue(_empty_event_called == 1, "Event handler never called.");
+ parcEventSignal_Destroy(&parcEventSignal);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+#include <pthread.h>
+
+static void *
+_run_scheduler(void *data)
+{
+ PARCEventScheduler *parcEventScheduler = (PARCEventScheduler *) data;
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+ return NULL;
+}
+
+static int _test_event_called = 0;
+
+static void
+_signal_event(int fd, PARCEventType flags, void *data)
+{
+ PARCEventSignal **parcEventSignal = (PARCEventSignal **) data;
+ _test_event_called++;
+ parcEventSignal_Stop(*parcEventSignal);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventSignal_Start_Stop)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEventSignal *parcEventSignal = parcEventSignal_Create(parcEventScheduler, SIGUSR1, PARCEventType_Signal | PARCEventType_Persist, _signal_event, &parcEventSignal);
+ assertNotNull(parcEventSignal, "parcEventSignal_Create returned a null reference");
+
+ parcEventSignal_Start(parcEventSignal);
+
+ pthread_t thread;
+ pthread_create(&thread, NULL, _run_scheduler, parcEventScheduler);
+
+ kill(getpid(), SIGUSR1);
+ pthread_join(thread, NULL);
+ assertTrue(_test_event_called == 1, "Event never called.");
+
+ parcEventSignal_Destroy(&parcEventSignal);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+static void
+_test_stop_event(int fd, PARCEventType flags, void *data)
+{
+ PARCEventSignal **parcEventSignal = (PARCEventSignal **) data;
+ _test_event_called++;
+ parcEventSignal_Stop(*parcEventSignal);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventSignal_Stop)
+{
+ _test_event_called = 0;
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+ PARCEventSignal *parcEventSignal = parcEventSignal_Create(parcEventScheduler, SIGUSR1, PARCEventType_Signal | PARCEventType_Persist, _test_stop_event, &parcEventSignal);
+ assertNotNull(parcEventSignal, "parcEventSignal_Create returned a null reference");
+
+ parcEventSignal_Start(parcEventSignal);
+ kill(getpid(), SIGUSR1);
+
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+ assertTrue(_test_event_called == 1, "Event never called.");
+
+ parcEventSignal_Destroy(&parcEventSignal);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventSignal);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_EventSocket.c b/libparc/parc/algol/test/test_parc_EventSocket.c
new file mode 100644
index 00000000..dbe8892b
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_EventSocket.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <arpa/inet.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_EventSocket.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_EventSocket.c"
+
+LONGBOW_TEST_RUNNER(parc_EventSocket)
+{
+ // 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(parc_EventSocket)
+{
+ parcEventSocket_EnableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventSocket)
+{
+ parcEventSocket_DisableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventSocket_Create_Destroy);
+}
+
+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 int _test_event_called = 0;
+
+static void
+listener_callback(int fd, struct sockaddr *sa, int socklen, void *user_data)
+{
+ _test_event_called++;
+}
+
+static int _test_error_event_called = 0;
+
+static void
+listener_error_callback(PARCEventScheduler *base, int error, char *errorString, void *addr_unix)
+{
+ _test_error_event_called++;
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventSocket_Create_Destroy)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(49009);
+ inet_pton(AF_INET, "127.0.0.1", &(addr.sin_addr));
+
+ PARCEventSocket *parcEventSocket = parcEventSocket_Create(parcEventScheduler,
+ listener_callback,
+ listener_error_callback,
+ NULL, NULL, 0);
+ assertNull(parcEventSocket, "parcEventSocket_Create didn't return an error when expected");
+
+ parcEventSocket = parcEventSocket_Create(parcEventScheduler,
+ listener_callback,
+ listener_error_callback,
+ NULL, (struct sockaddr *) &addr, sizeof(addr));
+ assertNotNull(parcEventSocket, "parcEventSocket_Create returned a null reference");
+
+ _parc_evconn_callback(NULL, 0, (struct sockaddr *) &addr, sizeof(addr), parcEventSocket);
+ assertTrue(_test_event_called == 1, "Listener callback wasn't triggered");
+ _parc_evconn_error_callback(NULL, parcEventSocket);
+ assertTrue(_test_error_event_called == 1, "Listener error callback wasn't triggered");
+
+ parcEventSocket_Destroy(&parcEventSocket);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventSocket);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_EventTimer.c b/libparc/parc/algol/test/test_parc_EventTimer.c
new file mode 100755
index 00000000..f6b9917e
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_EventTimer.c
@@ -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.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <pthread.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_EventTimer.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_EventTimer.c"
+
+LONGBOW_TEST_RUNNER(parc_EventTimer)
+{
+ // 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(parc_EventTimer)
+{
+ parcEventTimer_EnableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_EventTimer)
+{
+ parcEventTimer_DisableDebug();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventTimer_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventTimer_Start);
+ LONGBOW_RUN_TEST_CASE(Global, parc_EventTimer_Stop);
+}
+
+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 int _test_event_called = 0;
+
+static void
+_test_event(int fd, PARCEventType flags, void *data)
+{
+ _test_event_called++;
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventTimer_Create_Destroy)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventTimer *parcEventTimer = parcEventTimer_Create(parcEventScheduler, PARCEventType_None, _test_event, NULL);
+ assertNotNull(parcEventTimer, "parcEventTimer_Create returned a null reference");
+
+ parcEventTimer_Destroy(&parcEventTimer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventTimer_Start)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventTimer *parcEventTimer = parcEventTimer_Create(parcEventScheduler, PARCEventType_None, _test_event, NULL);
+ assertNotNull(parcEventTimer, "parcEventTimer_Create returned a null reference");
+
+ struct timeval timeout = { 1, 0 };
+ parcEventTimer_Start(parcEventTimer, &timeout);
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+ assertTrue(_test_event_called == 1, "Event never called.");
+
+ parcEventTimer_Destroy(&parcEventTimer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+static void
+_test_stop_event(int fd, PARCEventType flags, void *data)
+{
+ PARCEventTimer **parcEventTimer = (PARCEventTimer **) data;
+ _test_event_called++;
+ parcEventTimer_Stop(*parcEventTimer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_EventTimer_Stop)
+{
+ PARCEventScheduler *parcEventScheduler = parcEventScheduler_Create();
+ assertNotNull(parcEventScheduler, "parcEventScheduler_Create returned a null reference");
+
+ PARCEventTimer *parcEventTimer = parcEventTimer_Create(parcEventScheduler, PARCEventType_None | PARCEventType_Persist, _test_stop_event, &parcEventTimer);
+ assertNotNull(parcEventTimer, "parcEventTimer_Create returned a null reference");
+
+ _test_event_called = 0;
+ struct timeval timeout = { 1, 0 };
+ parcEventTimer_Start(parcEventTimer, &timeout);
+ parcEventScheduler_Start(parcEventScheduler, PARCEventSchedulerDispatchType_Blocking);
+ assertTrue(_test_event_called == 1, "Event never called.");
+
+ parcEventTimer_Destroy(&parcEventTimer);
+ parcEventScheduler_Destroy(&parcEventScheduler);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EventTimer);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_File.c b/libparc/parc/algol/test/test_parc_File.c
new file mode 100644
index 00000000..eccef210
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_File.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/unit-test.h>
+#include <fcntl.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_SafeMemory.h"
+#include "../parc_File.c"
+
+#define PATH_SEGMENT "A"
+
+LONGBOW_TEST_RUNNER(parc_File)
+{
+ // 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(Local);
+ LONGBOW_RUN_TEST_FIXTURE(AcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_File)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_File)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(AcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcFile_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease)
+{
+ longBowClipBoard_SetInt(testClipBoard, "initalAllocations", parcMemory_Outstanding());
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease)
+{
+ uint64_t initialAllocations = longBowClipBoard_GetAsInt(testClipBoard, "initalAllocations");
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (initialAllocations < outstandingAllocations) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcFile_AcquireRelease)
+{
+ char *root = "/tmp/test_parc_File";
+
+ PARCFile *file = parcFile_Create(root);
+
+ PARCFile *reference = parcFile_Acquire(file);
+
+ parcFile_Release(&reference);
+
+ parcFile_AssertValid(file);
+
+ parcFile_Release(&file);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcFile_CreateChild);
+ LONGBOW_RUN_TEST_CASE(Global, parcFile_CreateDeleteNewFile);
+ LONGBOW_RUN_TEST_CASE(Global, parcFile_CreateDelete_Directory);
+ LONGBOW_RUN_TEST_CASE(Global, parcFile_Exists);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowClipBoard_SetInt(testClipBoard, "initalAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint64_t initialAllocations = longBowClipBoard_GetAsInt(testClipBoard, "initalAllocations");
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (initialAllocations < outstandingAllocations) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcFile_Exists)
+{
+ char *root = "/tmp";
+
+ PARCFile *parent = parcFile_Create(root);
+
+ char *child = "foo";
+ PARCFile *file = parcFile_CreateChild(parent, child);
+
+ parcFile_CreateNewFile(file);
+
+ bool actual = parcFile_Exists(file);
+
+ assertTrue(actual, "Expected the file to exist.");
+
+ parcFile_Release(&file);
+ parcFile_Release(&parent);
+}
+
+LONGBOW_TEST_CASE(Global, parcFile_CreateChild)
+{
+ char *root = "/tmp";
+
+ PARCFile *parent = parcFile_Create(root);
+
+ char *child = "foo";
+ PARCFile *file = parcFile_CreateChild(parent, child);
+
+ char *actual = parcFile_ToString(file);
+
+ assertTrue(strcmp("/tmp/foo", actual) == 0,
+ "Expected %s, actual %s", "/tmp/foo", actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcFile_Release(&file);
+ parcFile_Release(&parent);
+}
+
+LONGBOW_TEST_CASE(Global, parcFile_CreateDeleteNewFile)
+{
+ char *name = "/tmp/test_parc_File";
+
+ PARCFile *file = parcFile_Create(name);
+
+ parcFile_CreateNewFile(file);
+
+ bool actual = parcFile_Delete(file);
+ assertTrue(actual, "Expected parcFile_Delete to return true.");
+
+ parcFile_Release(&file);
+}
+
+LONGBOW_TEST_CASE(Global, parcFile_CreateDelete_Directory)
+{
+ char *name = "/tmp/test_parc_File_directory";
+
+ PARCFile *directory = parcFile_Create(name);
+
+ parcFile_Mkdir(directory);
+
+ char *fileName = "foo";
+ PARCFile *file = parcFile_CreateChild(directory, fileName);
+
+ bool success = parcFile_CreateNewFile(file);
+ assertTrue(success, "Expected parcFile_CreateNewFile success");
+
+ bool actual = parcFile_Delete(directory);
+ assertTrue(actual, "Expected parcFile_Delete to return true.");
+
+ parcFile_Release(&file);
+ parcFile_Release(&directory);
+}
+
+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(parc_File);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_FileChunker.c b/libparc/parc/algol/test/test_parc_FileChunker.c
new file mode 100755
index 00000000..6060cff6
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_FileChunker.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_FileChunker.c"
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_BufferChunker.h>
+
+LONGBOW_TEST_RUNNER(parc_FileChunker)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_FileChunker)
+{
+ 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_FileChunker)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_CreateFromFile);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_File);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_FilePartial);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ForwardIterator_FileSmall);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_File);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_FilePartial);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_ReverseIterator_FileSmall);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Chunker_GetChunkSize);
+}
+
+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 void
+_createFile(char *fname, PARCBuffer *buffer)
+{
+ PARCFile *file = parcFile_Create(fname);
+ if (!parcFile_Exists(file)) {
+ parcFile_CreateNewFile(file);
+ }
+ PARCRandomAccessFile *fhandle = parcRandomAccessFile_Open(file);
+ parcFile_Release(&file);
+
+ parcRandomAccessFile_Write(fhandle, buffer);
+ parcRandomAccessFile_Close(fhandle);
+ parcRandomAccessFile_Release(&fhandle);
+}
+
+static void
+_deleteFile(char *fname)
+{
+ PARCFile *file = parcFile_Create(fname);
+ parcFile_Delete(file);
+ parcFile_Release(&file);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_CreateFromFile)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1024);
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+ parcBuffer_Flip(buffer);
+
+ _createFile("/tmp/file_chunker.tmp", buffer);
+
+ PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+
+ PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes
+ PARCFileChunker *copy = parcFileChunker_Acquire(chunker);
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+ assertNotNull(copy, "Expected non-NULL copy of Chunker");
+ parcFileChunker_Release(&copy);
+
+ parcFile_Release(&file);
+ parcFileChunker_Release(&chunker);
+
+ _deleteFile("/tmp/file_chunker.tmp");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_File)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1024);
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+ parcBuffer_Flip(buffer);
+
+ _createFile("/tmp/file_chunker.tmp", buffer);
+
+ PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+
+ PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcFileChunker_ForwardIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ for (size_t i = 0; i < 32; i++) {
+ assertTrue(contents[i] == count, "Expected %zu at index %zu, got %d", count, i, contents[i]);
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 32, "Expected to iterate over 32 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcFile_Release(&file);
+ parcFileChunker_Release(&chunker);
+
+ _deleteFile("/tmp/file_chunker.tmp");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_FilePartial)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1030);
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+
+ // Special 0xFF to mark the end...
+ for (int i = 0; i < 6; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+ parcBuffer_Flip(buffer);
+
+ _createFile("/tmp/file_chunker.tmp", buffer);
+
+ PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+
+ PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcFileChunker_ForwardIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ if (count < 32) {
+ for (size_t i = 0; i < 32; i++) {
+ assertTrue(contents[i] == count, "Expected %zu at index %zu, got %d", count, i, contents[i]);
+ }
+ } else {
+ for (size_t i = 0; i < 6; i++) {
+ assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]);
+ }
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 33, "Expected to iterate over 33 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcFile_Release(&file);
+ parcFileChunker_Release(&chunker);
+
+ _deleteFile("/tmp/file_chunker.tmp");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ForwardIterator_FileSmall)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(16);
+
+ // Special 0xFF to mark the end...
+ for (int i = 0; i < 16; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+ parcBuffer_Flip(buffer);
+
+ _createFile("/tmp/file_chunker.tmp", buffer);
+
+ PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+
+ PARCFileChunker *chunker = parcFileChunker_Create(file, 4096); // each chunk is 1024 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcFileChunker_ForwardIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ for (size_t i = 0; i < 16; i++) {
+ assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]);
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 1, "Expected to iterate over 1 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcFile_Release(&file);
+ parcFileChunker_Release(&chunker);
+
+ _deleteFile("/tmp/file_chunker.tmp");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_File)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1024);
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+ parcBuffer_Flip(buffer);
+
+ _createFile("/tmp/file_chunker.tmp", buffer);
+
+ PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+
+ PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcFileChunker_ReverseIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ for (size_t i = 0; i < 32; i++) {
+ assertTrue(contents[i] == (31 - count), "Expected %zu at index %zu, got %d", count, i, contents[i]);
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 32, "Expected to iterate over 32 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcFile_Release(&file);
+ parcFileChunker_Release(&chunker);
+
+ _deleteFile("/tmp/file_chunker.tmp");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_FilePartial)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1030);
+
+ // Special 0xFF to mark the start...
+ for (int i = 0; i < 6; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+
+ for (size_t i = 0; i < 32; i++) {
+ for (size_t j = 0; j < 32; j++) {
+ parcBuffer_PutUint8(buffer, i);
+ }
+ }
+ parcBuffer_Flip(buffer);
+
+ _createFile("/tmp/file_chunker.tmp", buffer);
+
+ PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+
+ PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcFileChunker_ReverseIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ if (count < 32) {
+ for (size_t i = 0; i < 32; i++) {
+ assertTrue(contents[i] == (31 - count), "Expected %zu at index %zu, got %d", (31 - count), i, contents[i]);
+ }
+ } else {
+ for (size_t i = 0; i < 6; i++) {
+ assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]);
+ }
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 33, "Expected to iterate over 33 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcFile_Release(&file);
+ parcFileChunker_Release(&chunker);
+
+ _deleteFile("/tmp/file_chunker.tmp");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_ReverseIterator_FileSmall)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1030);
+
+ // Special 0xFF to mark the start...
+ for (int i = 0; i < 6; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+ parcBuffer_Flip(buffer);
+
+ _createFile("/tmp/file_chunker.tmp", buffer);
+
+ PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+
+ PARCFileChunker *chunker = parcFileChunker_Create(file, 32); // each chunk is 32 bytes
+ assertNotNull(chunker, "Expected non-NULL Chunker");
+
+ PARCIterator *itr = parcFileChunker_ReverseIterator(chunker);
+ size_t count = 0;
+ while (parcIterator_HasNext(itr)) {
+ PARCBuffer *payload = (PARCBuffer *) parcIterator_Next(itr);
+
+ uint8_t *contents = parcBuffer_Overlay(payload, 0);
+ for (size_t i = 0; i < 6; i++) {
+ assertTrue(contents[i] == 0xFF, "Expected %zu at index %zu, got %d", (size_t) 0xFF, i, contents[i]);
+ }
+ count++;
+
+ parcBuffer_Release(&payload);
+ }
+ assertTrue(count == 1, "Expected to iterate over 1 content objects from the chunker, but for %zu", count);
+ parcIterator_Release(&itr);
+
+ parcFile_Release(&file);
+ parcFileChunker_Release(&chunker);
+
+ _deleteFile("/tmp/file_chunker.tmp");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Chunker_GetChunkSize)
+{
+ size_t expectedChunkSize = 32;
+ PARCBuffer *buffer = parcBuffer_Allocate(1030);
+
+ // Special 0xFF to mark the start...
+ for (int i = 0; i < 6; i++) {
+ parcBuffer_PutUint8(buffer, 0xFF);
+ }
+ parcBuffer_Flip(buffer);
+
+ _createFile("/tmp/file_chunker.tmp", buffer);
+
+ PARCFile *file = parcFile_Create("/tmp/file_chunker.tmp");
+ PARCFileChunker *chunker = parcFileChunker_Create(file, expectedChunkSize); // each chunk is 32 bytes
+
+ size_t actualChunkSize = parcBufferChunker_GetChunkSize(chunker);
+
+ assertTrue(actualChunkSize == expectedChunkSize, "Expected chunk size of %zu, got %zu", expectedChunkSize, actualChunkSize);
+
+ parcFile_Release(&file);
+ parcFileChunker_Release(&chunker);
+
+ _deleteFile("/tmp/file_chunker.tmp");
+
+ parcBuffer_Release(&buffer);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_FileChunker);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_FileInputStream.c b/libparc/parc/algol/test/test_parc_FileInputStream.c
new file mode 100755
index 00000000..49032050
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_FileInputStream.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.
+ */
+
+/**
+ * @header <#Headline Name#>
+ * @abstract <#Abstract#>
+ * @discussion
+ * <#Discussion#>
+ *
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_FileInputStream.c"
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_File.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(test_parc_FileInputStream)
+{
+ // 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_parc_FileInputStream)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_FileInputStream)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcFileInputStream_Open);
+ LONGBOW_RUN_TEST_CASE(Global, parcFileInputStream_ReadFile);
+}
+
+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, parcFileInputStream_Open)
+{
+ PARCFile *file = parcFile_Create("test_parc_FileInputStream");
+ PARCFileInputStream *stream = parcFileInputStream_Open(file);
+
+ parcFileInputStream_Release(&stream);
+ parcFile_Release(&file);
+}
+
+LONGBOW_TEST_CASE(Global, parcFileInputStream_ReadFile)
+{
+ PARCFile *file = parcFile_Create("test_parc_FileInputStream");
+ PARCFileInputStream *stream = parcFileInputStream_Open(file);
+
+ PARCBuffer *actual = parcFileInputStream_ReadFile(stream);
+ assertNotNull(actual, "Expected non-null result from parcFileInputStream_ReadFile");
+
+ parcBuffer_Flip(actual);
+
+ assertTrue(parcBuffer_HasRemaining(actual), "Expected the buffer to contain data.");
+
+ parcBuffer_Release(&actual);
+ parcFileInputStream_Release(&stream);
+ parcFile_Release(&file);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_FileInputStream);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_FileOutputStream.c b/libparc/parc/algol/test/test_parc_FileOutputStream.c
new file mode 100755
index 00000000..aa4236ae
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_FileOutputStream.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 <LongBow/unit-test.h>
+#include <fcntl.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_SafeMemory.h"
+#include "../parc_FileOutputStream.c"
+
+#define PATH_SEGMENT "A"
+
+LONGBOW_TEST_RUNNER(parc_FileOutputStream)
+{
+ // 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(Local);
+ LONGBOW_RUN_TEST_FIXTURE(AcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_FileOutputStream)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_FileOutputStream)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(AcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcFileOutputStream_Create);
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcFileOutputStream_Release);
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcFileOutputStream_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease)
+{
+ unlink("/tmp/test_parc_FileOutputStream");
+ 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(AcquireRelease, parcFileOutputStream_Create)
+{
+ PARCFileOutputStream *stream = parcFileOutputStream_Create(open("/tmp/test_parc_FileOutputStream", O_CREAT | O_WRONLY | O_TRUNC, 0600));
+ assertNotNull(stream, "Expected a non-null pointer");
+
+ parcFileOutputStream_Release(&stream);
+ assertNull(stream, "Expected parcFileOutputStream_Release to null the pointer");
+ unlink("/tmp/test_parc_FileOutputStream");
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcFileOutputStream_Release)
+{
+ PARCFileOutputStream *stream = parcFileOutputStream_Create(open("/tmp/test_parc_FileOutputStream", O_CREAT | O_WRONLY | O_TRUNC, 0600));
+ assertNotNull(stream, "Expected a non-null pointer");
+
+ parcFileOutputStream_Release(&stream);
+ assertNull(stream, "Expected parcFileOutputStream_Release to null the pointer");
+ unlink("/tmp/test_parc_FileOutputStream");
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcFileOutputStream_AcquireRelease)
+{
+ PARCFileOutputStream *stream = parcFileOutputStream_Create(open("/tmp/test_parc_FileOutputStream", O_CREAT | O_WRONLY | O_TRUNC, 0600));
+ assertNotNull(stream, "Expected a non-null pointer");
+
+ PARCFileOutputStream *reference = parcFileOutputStream_Acquire(stream);
+ assertTrue(stream == reference, "Expected the reference to be equal to the original.");
+
+ parcFileOutputStream_Release(&stream);
+ assertNull(stream, "Expected parcFileOutputStream_Release to null the pointer");
+
+ parcFileOutputStream_Release(&reference);
+ unlink("/tmp/test_parc_FileOutputStream");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcFileOutputStream_Write);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ unlink("/tmp/test_parc_FileOutputStream");
+
+ 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, parcFileOutputStream_Write)
+{
+ PARCFileOutputStream *stream =
+ parcFileOutputStream_Create(open("/tmp/test_parc_FileOutputStream", O_CREAT | O_WRONLY | O_TRUNC, 0600));
+
+ PARCBuffer *buffer = parcBuffer_Allocate(16 * 1024 * 1024);
+
+ parcFileOutputStream_Write(stream, buffer);
+
+ assertFalse(parcBuffer_HasRemaining(buffer), "Expected the buffer to be emtpy");
+
+ parcBuffer_Release(&buffer);
+
+ parcFileOutputStream_Release(&stream);
+ unlink("/tmp/test_parc_FileOutputStream");
+}
+
+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(parc_FileOutputStream);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Hash.c b/libparc/parc/algol/test/test_parc_Hash.c
new file mode 100755
index 00000000..cc92a867
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Hash.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 "../parc_Hash.c"
+
+#include <LongBow/testing.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(parc_Hash)
+{
+ // 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(parc_Hash)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Hash)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_Update);
+ LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_UpdateUint32);
+ LONGBOW_RUN_TEST_CASE(Global, parcHash32Bit_Hash);
+
+ LONGBOW_RUN_TEST_CASE(Global, parc_Hash32_Data);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Hash32_Int32);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Hash32_Int64);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Hash64_Data);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Hash64_Int32);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Hash64_Int64);
+}
+
+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, parcHash32Bit_Create)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcHash32Bit_Acquire)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcHash32Bit_Release)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcHash32Bit_Update)
+{
+ PARCHash32Bits *hash = parcHash32Bits_Create();
+ parcHash32Bits_Update(hash, "123", 3);
+ uint32_t value = parcHash32Bits_Hash(hash);
+ assertTrue(value != 0, "Expected a non-zero (non-initial) value");
+
+ parcHash32Bits_Release(&hash);
+}
+
+LONGBOW_TEST_CASE(Global, parcHash32Bit_UpdateUint32)
+{
+ PARCHash32Bits *hash = parcHash32Bits_Create();
+ parcHash32Bits_UpdateUint32(hash, 123);
+ uint32_t value = parcHash32Bits_Hash(hash);
+ assertTrue(value != 0, "Expected a non-zero (non-initial) value");
+
+ parcHash32Bits_Release(&hash);
+}
+
+LONGBOW_TEST_CASE(Global, parcHash32Bit_Hash)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parc_Hash32_Data)
+{
+ char *data1 = "Hello World";
+ char *data2 = "Hello World1";
+ char *data3 = "Hello World2";
+
+ char data4[20];
+ strncpy(data4, data1, sizeof(data4));
+
+ uint32_t hash1 = parcHash32_Data(data1, strlen(data1));
+ uint32_t hash2 = parcHash32_Data(data2, strlen(data2));
+ uint32_t hash3 = parcHash32_Data(data3, strlen(data3));
+ uint32_t hash4 = parcHash32_Data(data4, strlen(data4));
+
+ assertTrue(hash1 != 0, "Hash is 0, unlikely");
+ assertTrue(hash2 != 0, "Hash is 0, unlikely");
+ assertTrue(hash3 != 0, "Hash is 0, unlikely");
+ assertTrue(hash4 != 0, "Hash is 0, unlikely");
+ assertTrue(hash1 != hash2, "Hash collision, unlikely");
+ assertTrue(hash3 != hash2, "Hash collision, unlikely");
+ assertTrue(hash3 != hash1, "Hash collision, unlikely");
+ assertTrue(hash1 == hash4, "Hash different for same content");
+}
+
+LONGBOW_TEST_CASE(Global, parc_Hash32_Int32)
+{
+ uint32_t data1 = 12345;
+ uint32_t data2 = 12346;
+ uint32_t data3 = 12345;
+
+ uint32_t hash1 = parcHash32_Int32(data1);
+ uint32_t hash2 = parcHash32_Int32(data2);
+ uint32_t hash3 = parcHash32_Int32(data3);
+
+ assertTrue(hash1 != 0, "Hash is 0, unlikely");
+ assertTrue(hash2 != 0, "Hash is 0, unlikely");
+ assertTrue(hash3 != 0, "Hash is 0, unlikely");
+ assertTrue(hash1 != hash2, "Hash collision, unlikely");
+ assertTrue(hash1 == hash3, "Hash different for same content");
+}
+
+LONGBOW_TEST_CASE(Global, parc_Hash32_Int64)
+{
+ uint64_t data1 = 10010010012345;
+ uint64_t data2 = 10010010012346;
+ uint64_t data3 = 10010010012345;
+
+ uint32_t hash1 = parcHash32_Int64(data1);
+ uint32_t hash2 = parcHash32_Int64(data2);
+ uint32_t hash3 = parcHash32_Int64(data3);
+
+ assertTrue(hash1 != 0, "Hash is 0, unlikely");
+ assertTrue(hash2 != 0, "Hash is 0, unlikely");
+ assertTrue(hash3 != 0, "Hash is 0, unlikely");
+ assertTrue(hash1 != hash2, "Hash collision, unlikely");
+ assertTrue(hash1 == hash3, "Hash different for same content");
+}
+
+LONGBOW_TEST_CASE(Global, parc_Hash64_Data)
+{
+ char *data1 = "Hello World";
+ char *data2 = "Hello World1";
+ char *data3 = "Hello World2";
+
+ char data4[20];
+ strncpy(data4, data1, sizeof(data4));
+
+ uint64_t hash1 = parcHash64_Data(data1, strlen(data1));
+ uint64_t hash2 = parcHash64_Data(data2, strlen(data2));
+ uint64_t hash3 = parcHash64_Data(data3, strlen(data3));
+ uint64_t hash4 = parcHash64_Data(data4, strlen(data4));
+
+ assertTrue(hash1 != 0, "Hash is 0, unlikely");
+ assertTrue(hash2 != 0, "Hash is 0, unlikely");
+ assertTrue(hash3 != 0, "Hash is 0, unlikely");
+ assertTrue(hash4 != 0, "Hash is 0, unlikely");
+ assertTrue(hash1 != hash2, "Hash collision, unlikely");
+ assertTrue(hash3 != hash2, "Hash collision, unlikely");
+ assertTrue(hash3 != hash1, "Hash collision, unlikely");
+ assertTrue(hash1 == hash4, "Hash different for same content");
+}
+
+LONGBOW_TEST_CASE(Global, parc_Hash64_Int32)
+{
+ uint32_t data1 = 12345;
+ uint32_t data2 = 12346;
+ uint32_t data3 = 12345;
+
+ uint64_t hash1 = parcHash64_Int32(data1);
+ uint64_t hash2 = parcHash64_Int32(data2);
+ uint64_t hash3 = parcHash64_Int32(data3);
+
+ assertTrue(hash1 != 0, "Hash is 0, unlikely");
+ assertTrue(hash2 != 0, "Hash is 0, unlikely");
+ assertTrue(hash3 != 0, "Hash is 0, unlikely");
+ assertTrue(hash1 != hash2, "Hash collision, unlikely");
+ assertTrue(hash1 == hash3, "Hash different for same content");
+}
+
+LONGBOW_TEST_CASE(Global, parc_Hash64_Int64)
+{
+ uint64_t data1 = 10010010012345;
+ uint64_t data2 = 10010010012346;
+ uint64_t data3 = 10010010012345;
+
+ uint64_t hash1 = parcHash64_Int64(data1);
+ uint64_t hash2 = parcHash64_Int64(data2);
+ uint64_t hash3 = parcHash64_Int64(data3);
+
+ assertTrue(hash1 != 0, "Hash is 0, unlikely");
+ assertTrue(hash2 != 0, "Hash is 0, unlikely");
+ assertTrue(hash3 != 0, "Hash is 0, unlikely");
+ assertTrue(hash1 != hash2, "Hash collision, unlikely");
+ assertTrue(hash1 == hash3, "Hash different for same content");
+}
+
+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(parc_Hash);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_HashCode.c b/libparc/parc/algol/test/test_parc_HashCode.c
new file mode 100755
index 00000000..a5b21137
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_HashCode.c
@@ -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.
+ */
+
+/** *
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_HashCode.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+LONGBOW_TEST_RUNNER(test_parc_HashCode)
+{
+ // 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_parc_HashCode)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_HashCode)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCode_HashImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCode_HashHashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCode_Hash);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCode_HashImpl)
+{
+ PARCHashCode lastValue = 0;
+ uint8_t *memory = (uint8_t *) "1234";
+ size_t length = 4;
+
+ PARCHashCode expected = 3316911679945239212ULL;
+ PARCHashCode actual = parcHashCode_HashImpl(memory, length, lastValue);
+
+ assertTrue(expected == actual, "Expected %" PRIPARCHashCode " actual %" PRIPARCHashCode, expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCode_HashHashCode)
+{
+ PARCHashCode lastValue = 0;
+ uint8_t *memory = (uint8_t *) "1234";
+ size_t length = 4;
+
+ PARCHashCode lastHash = parcHashCode_HashImpl(memory, length, lastValue);
+
+ PARCHashCode hashedHash = parcHashCode_HashHashCode(lastHash, 123456);
+
+ assertTrue(lastHash != 0, "Expected a non zero hash value for lastHash");
+ assertTrue(hashedHash != 0, "Expected a non zero hash value for hashedHash");
+ assertTrue(lastHash != hashedHash, "Expected different hash values for hashedHash and lastHash");
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCode_Hash)
+{
+ char *testString1 = "this is some test data";
+ char *testString2 = "this is different test data";
+
+ PARCHashCode hash1 = parcHashCode_Hash((uint8_t *) testString1, strlen(testString1));
+ PARCHashCode hash2 = parcHashCode_Hash((uint8_t *) testString2, strlen(testString2));
+
+ assertTrue(hash1 != 0, "Expected a non zero hash value for testString1");
+ assertTrue(hash2 != 0, "Expected a non zero hash value for testString2");
+ assertTrue(hash1 != hash2, "Expected different hash values for testString1 and testString2");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_HashCode);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_HashCodeTable.c b/libparc/parc/algol/test/test_parc_HashCodeTable.c
new file mode 100755
index 00000000..c2adf9d2
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_HashCodeTable.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <time.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <sys/time.h>
+
+#include <LongBow/unit-test.h>
+
+#include "../parc_HashCodeTable.c"
+
+#include <parc/algol/parc_SafeMemory.h>
+
+// ==============================
+// The objects to put in the hash table. We have a separate key class and data class
+
+typedef struct test_key_class {
+ unsigned key_value;
+ unsigned hash_value;
+} TestKeyClass;
+
+typedef struct test_data_class {
+ unsigned data_value;
+} TestDataClass;
+
+static bool
+TestKeyClass_Equals(const void *a, const void *b)
+{
+ return ((TestKeyClass *) a)->key_value == ((TestKeyClass *) b)->key_value;
+}
+
+static HashCodeType
+TestKeyClass_Hash(const void *a)
+{
+ return ((TestKeyClass *) a)->hash_value;
+}
+
+static void
+TestKeyClassDestroy(void **aPtr)
+{
+ parcMemory_Deallocate((void **) aPtr);
+ aPtr = NULL;
+}
+
+static void
+TestDataClassDestroy(void **aPtr)
+{
+ parcMemory_Deallocate((void **) aPtr);
+ aPtr = NULL;
+}
+
+typedef struct truth_table_entry {
+ unsigned key_value;
+ unsigned hash_code;
+ unsigned data_value;
+} TruthTableEntry;
+
+// ==============================
+
+
+LONGBOW_TEST_RUNNER(parc_HashCodeTable)
+{
+ // 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(parc_HashCodeTable)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_HashCodeTable)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Add_Get);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Create_Size);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Del);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Add_DuplicateHashes);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_Add_DuplicateValues);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcHashCodeTable_BigTable);
+}
+
+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, parcHashCodeTable_Add_Get)
+{
+ const int testsize = 4096;
+ PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy);
+ TruthTableEntry *truthtable = parcMemory_Allocate(sizeof(TruthTableEntry) * testsize);
+ assertNotNull(truthtable, "parcMemory_Allocate(%zu) returned NULL", sizeof(TruthTableEntry) * testsize);
+ int i;
+ int fd = open("/dev/urandom", O_RDONLY);
+
+ if (fd == -1) {
+ assertFalse(fd == -1, "Error opening random number generator: %s", strerror(errno));
+ }
+
+ ssize_t nread = read(fd, truthtable, sizeof(TruthTableEntry) * testsize);
+ assertTrue(nread > 0, "Error using read");
+ close(fd);
+
+ for (i = 0; i < testsize; i++) {
+ TestKeyClass *key = parcMemory_AllocateAndClear(sizeof(TestKeyClass));
+ assertNotNull(key, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass));
+ TestDataClass *data = parcMemory_AllocateAndClear(sizeof(TestDataClass));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass));
+
+ key->key_value = truthtable[i].key_value;
+ key->hash_value = truthtable[i].hash_code;
+ data->data_value = truthtable[i].data_value;
+
+ bool success = parcHashCodeTable_Add(table, key, data);
+ assertTrue(success, "Failed inserting value");
+ }
+
+ // now retrieve them
+ for (i = 0; i < testsize; i++) {
+ TestKeyClass lookupkey;
+ lookupkey.key_value = truthtable[i].key_value;
+ lookupkey.hash_value = truthtable[i].hash_code;
+
+ TestDataClass *data = parcHashCodeTable_Get(table, &lookupkey);
+ assertTrue(data->data_value == truthtable[i].data_value, "Data value incorrect");
+ }
+
+ parcHashCodeTable_Destroy(&table);
+ parcMemory_Deallocate((void **) &truthtable);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCodeTable_Create)
+{
+ PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy);
+
+ assertNotNull(table, "table came back as null");
+ assertTrue(table->hashtable.tableSize == 0, "Hash table initialized to wrong size");
+ assertTrue(table->hashtable.tableLimit == MIN_SIZE, "Initial table limit size is wrong");
+ assertTrue(table->keyEqualsFunc == TestKeyClass_Equals, "KeyEqualsFunc wrong");
+ assertTrue(table->keyHashCodeFunc == TestKeyClass_Hash, "KeyHashFunc wrong");
+ assertTrue(table->keyDestroyer == TestKeyClassDestroy, "KeyDestroyer wrong");
+ assertTrue(table->dataDestroyer == TestDataClassDestroy, "DataDestroyer wrong");
+
+ parcHashCodeTable_Destroy(&table);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCodeTable_Create_Size)
+{
+ PARCHashCodeTable *table = parcHashCodeTable_Create_Size(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy, 16);
+
+ assertNotNull(table, "table came back as null");
+ assertTrue(table->hashtable.tableLimit == 16, "Initial table limit size is wrong");
+ parcHashCodeTable_Destroy(&table);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCodeTable_Del)
+{
+ const int testsize = 6;
+ PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy);
+ TruthTableEntry *truthtable = parcMemory_Allocate(sizeof(TruthTableEntry) * testsize);
+ assertNotNull(truthtable, "parcMemory_Allocate(%zu) returned NULL", sizeof(TruthTableEntry) * testsize);
+ int i;
+ int fd = open("/dev/urandom", O_RDONLY);
+
+ if (fd == -1) {
+ assertFalse(fd == -1, "Error opening random number generator: %s", strerror(errno));
+ }
+
+ ssize_t nread = read(fd, truthtable, sizeof(TruthTableEntry) * testsize);
+ assertTrue(nread > 0, "Error using read");
+ close(fd);
+
+ for (i = 0; i < testsize; i++) {
+ TestKeyClass *key = parcMemory_AllocateAndClear(sizeof(TestKeyClass));
+ assertNotNull(key, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass));
+ TestDataClass *data = parcMemory_AllocateAndClear(sizeof(TestDataClass));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass));
+
+ key->key_value = truthtable[i].key_value;
+ key->hash_value = truthtable[i].hash_code;
+ data->data_value = truthtable[i].data_value;
+
+ bool success = parcHashCodeTable_Add(table, key, data);
+ assertTrue(success, "Failed inserting value");
+ }
+
+ // delete the last one
+ {
+ TestKeyClass lookupkey;
+
+ lookupkey.key_value = truthtable[testsize - 1].key_value;
+ lookupkey.hash_value = truthtable[testsize - 1].hash_code;
+
+ parcHashCodeTable_Del(table, &lookupkey);
+ assertTrue(table->hashtable.tableSize == testsize - 1, "tableSize wrong");
+ }
+
+ for (i = 0; i < testsize - 1; i++) {
+ TestKeyClass lookupkey;
+ lookupkey.key_value = truthtable[i].key_value;
+ lookupkey.hash_value = truthtable[i].hash_code;
+
+ TestDataClass *data = parcHashCodeTable_Get(table, &lookupkey);
+ assertTrue(data->data_value == truthtable[i].data_value, "Data value incorrect");
+ }
+
+ for (i = testsize - 1; i < testsize; i++) {
+ TestKeyClass lookupkey;
+ lookupkey.key_value = truthtable[i].key_value;
+ lookupkey.hash_value = truthtable[i].hash_code;
+
+ TestDataClass *data = parcHashCodeTable_Get(table, &lookupkey);
+ assertNull(data, "Should not have returned deleted value");
+ }
+ parcHashCodeTable_Destroy(&table);
+ parcMemory_Deallocate((void **) &truthtable);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCodeTable_Add_DuplicateHashes)
+{
+ PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy);
+
+ TestKeyClass *key1 = parcMemory_AllocateAndClear(sizeof(TestKeyClass));
+ assertNotNull(key1, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass));
+ TestKeyClass *key2 = parcMemory_AllocateAndClear(sizeof(TestKeyClass));
+ assertNotNull(key2, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass));
+ TestDataClass *data1 = parcMemory_AllocateAndClear(sizeof(TestDataClass));
+ assertNotNull(data1, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass));
+ TestDataClass *data2 = parcMemory_AllocateAndClear(sizeof(TestDataClass));
+ assertNotNull(data2, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass));
+ TestDataClass *test;
+ bool success;
+
+ *key1 = (TestKeyClass) { .key_value = 1, .hash_value = 2 };
+ *key2 = (TestKeyClass) { .key_value = 3, .hash_value = 2 };
+ data1->data_value = 11;
+ data2->data_value = 22;
+
+ success = parcHashCodeTable_Add(table, key1, data1);
+ assertTrue(success, "Failed to add value");
+
+ success = parcHashCodeTable_Add(table, key2, data2);
+ assertTrue(success, "Failed to add value");
+
+ // value 3 should be in position 3
+ test = parcHashCodeTable_Get(table, key1);
+ assertNotNull(test, "returned null on get");
+ assertTrue(test->data_value == 11, "Got wrong value back for key1");
+
+ test = parcHashCodeTable_Get(table, key2);
+ assertNotNull(test, "returned null on get");
+ assertTrue(test->data_value == 22, "Got wrong value back for key1");
+
+ parcHashCodeTable_Destroy(&table);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCodeTable_Add_DuplicateValues)
+{
+ PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy);
+
+ TestKeyClass *key1 = parcMemory_AllocateAndClear(sizeof(TestKeyClass));
+ assertNotNull(key1, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass));
+ TestKeyClass *key2 = parcMemory_AllocateAndClear(sizeof(TestKeyClass));
+ assertNotNull(key2, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass));
+ TestDataClass *data1 = parcMemory_AllocateAndClear(sizeof(TestDataClass));
+ assertNotNull(data1, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass));
+ TestDataClass *data2 = parcMemory_AllocateAndClear(sizeof(TestDataClass));
+ assertNotNull(data2, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass));
+ TestDataClass *test;
+ bool success;
+
+ *key1 = (TestKeyClass) { .key_value = 1, .hash_value = 2 };
+ *key2 = (TestKeyClass) { .key_value = 1, .hash_value = 2 };
+ data1->data_value = 11;
+ data2->data_value = 22;
+
+ success = parcHashCodeTable_Add(table, key1, data1);
+ assertTrue(success, "Failed to add value");
+
+ success = parcHashCodeTable_Add(table, key2, data2);
+ assertFalse(success, "Second add should have failed on duplicate key");
+
+ // value 3 should be in position 3
+ test = parcHashCodeTable_Get(table, key1);
+ assertNotNull(test, "returned null on get");
+ assertTrue(test->data_value == 11, "Got wrong value back for key1");
+
+ parcHashCodeTable_Destroy(&table);
+ parcMemory_Deallocate((void **) &key2);
+ parcMemory_Deallocate((void **) &data2);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashCodeTable_BigTable)
+{
+ PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy);
+
+ struct timeval t0, t1;
+
+ gettimeofday(&t0, NULL);
+
+ int loops = 1000;
+ for (int i = 0; i < loops; i++) {
+ TestKeyClass *key = parcMemory_AllocateAndClear(sizeof(TestKeyClass));
+ assertNotNull(key, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass));
+ TestDataClass *data = parcMemory_AllocateAndClear(sizeof(TestDataClass));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass));
+
+ *key = (TestKeyClass) { .key_value = i, .hash_value = i };
+ data->data_value = i;
+
+ bool success = parcHashCodeTable_Add(table, key, data);
+ assertTrue(success, "Failed to add value");
+ }
+ gettimeofday(&t1, NULL);
+
+ timersub(&t1, &t0, &t1);
+ double sec = t1.tv_sec + t1.tv_usec * 1E-6;
+ printf("expand count %u, sec = %.3f, sec/add = %.9f\n", table->expandCount, sec, sec / loops);
+
+ gettimeofday(&t0, NULL);
+ parcHashCodeTable_Destroy(&table);
+ gettimeofday(&t1, NULL);
+
+ timersub(&t1, &t0, &t1);
+ sec = t1.tv_sec + t1.tv_usec * 1E-6;
+ printf("destroy sec = %.3f, sec/add = %.9f\n", sec, sec / loops);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _findIndex);
+}
+
+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, _findIndex)
+{
+ PARCHashCodeTable *table = parcHashCodeTable_Create(TestKeyClass_Equals, TestKeyClass_Hash, TestKeyClassDestroy, TestDataClassDestroy);
+
+ // stick a data element in the middle of the table
+ TestKeyClass *key = parcMemory_AllocateAndClear(sizeof(TestKeyClass));
+ assertNotNull(key, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestKeyClass));
+ TestDataClass *data = parcMemory_AllocateAndClear(sizeof(TestDataClass));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestDataClass));
+
+ key->key_value = 1;
+ key->hash_value = 37;
+ data->data_value = 7;
+
+ table->hashtable.entries[37].key = key;
+ table->hashtable.entries[37].hashcode = key->hash_value;
+ table->hashtable.entries[37].data = data;
+
+ size_t index;
+ bool success = _findIndex(table, key, &index);
+ assertTrue(success, "FindIndex did not find known value");
+ assertTrue(index == 37, "FindIndex returned wrong value");
+
+
+ parcHashCodeTable_Destroy(&table);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_HashCodeTable);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_HashMap.c b/libparc/parc/algol/test/test_parc_HashMap.c
new file mode 100644
index 00000000..1b071f44
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_HashMap.c
@@ -0,0 +1,915 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_HashMap.c"
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_StdlibMemory.h>
+
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/testing/parc_MemoryTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_HashMap)
+{
+ // 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(Static);
+ LONGBOW_RUN_TEST_FIXTURE(CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(ObjectContract);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_HashMap)
+{
+ 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_HashMap)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateCapacity0);
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateCapacityNominal);
+}
+
+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)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+ assertNotNull(instance, "Expeced non-null result from parcHashMap_Create();");
+ parcObjectTesting_AssertAcquireReleaseContract(parcHashMap_Acquire, instance);
+
+ parcHashMap_Release(&instance);
+ assertNull(instance, "Expeced null result from parcHashMap_Release();");
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateCapacity0)
+{
+ const size_t CAPACITY = 0;
+ PARCHashMap *instance = parcHashMap_CreateCapacity(CAPACITY);
+ assertNotNull(instance, "Expeced non-null result from parcHashMap_Create();");
+ parcObjectTesting_AssertAcquireReleaseContract(parcHashMap_Acquire, instance);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateCapacityNominal)
+{
+ const size_t CAPACITY = 10000;
+ PARCHashMap *instance = parcHashMap_CreateCapacity(CAPACITY);
+ assertNotNull(instance, "Expeced non-null result from parcHashMap_Create();");
+ parcObjectTesting_AssertAcquireReleaseContract(parcHashMap_Acquire, instance);
+ assertTrue(instance->capacity == CAPACITY, "Expect capacity to be %zu", CAPACITY);
+ assertTrue(instance->size == 0, "Expect size to be 0");
+
+ //Make sure all the buckets exist
+ for (size_t i = 0; i < CAPACITY; ++i) {
+ assertNull(instance->buckets[i], "Expect the hashmap to be clear");
+ }
+
+ parcHashMap_Release(&instance);
+ assertNull(instance, "Expeced null result from parcHashMap_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(ObjectContract)
+{
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_Copy);
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_Display);
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_Equals);
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_HashCode_Empty);
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_HashCode_NonEmpty);
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_IsValid);
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_AssertValid);
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_ToJSON);
+ LONGBOW_RUN_TEST_CASE(ObjectContract, parcHashMap_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(ObjectContract)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(ObjectContract)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_Copy)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+ PARCHashMap *copy = parcHashMap_Copy(instance);
+
+ assertTrue(parcHashMap_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcHashMap_Release(&instance);
+ parcHashMap_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_Display)
+{
+ PARCHashMap *x = parcHashMap_Create();
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+ parcHashMap_Put(x, key, value);
+ parcHashMap_Display(x, 0);
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&x);
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_Equals)
+{
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ PARCHashMap *x = parcHashMap_Create();
+ parcHashMap_Put(x, key, value);
+ PARCHashMap *y = parcHashMap_Create();
+ parcHashMap_Put(y, key, value);
+ PARCHashMap *z = parcHashMap_Create();
+ parcHashMap_Put(z, key, value);
+
+ PARCHashMap *u1 = parcHashMap_Create();
+
+ PARCHashMap *u2 = parcHashMap_Create();
+ parcHashMap_Put(u2, key, value);
+
+ parcObjectTesting_AssertEquals(x, y, z, u1, NULL);
+
+ parcHashMap_Release(&x);
+ parcHashMap_Release(&y);
+ parcHashMap_Release(&z);
+ parcHashMap_Release(&u1);
+ parcHashMap_Release(&u2);
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_HashCode_Empty)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCHashCode code = parcHashMap_HashCode(instance);
+
+ assertTrue(code == 0, "Expected 0, actual %" PRIPARCHashCode, code);
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_HashCode_NonEmpty)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+ parcHashMap_Put(instance, key, value);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ PARCHashCode code = parcHashMap_HashCode(instance);
+ assertTrue(code != 0, "Expected a non-zero hash code, actual %" PRIPARCHashCode, code);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_IsValid)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+ parcHashMap_Put(instance, key, value);
+ assertTrue(parcHashMap_IsValid(instance), "Expected parcHashMap_Create to result in a valid instance.");
+
+ parcHashMap_Release(&instance);
+ assertFalse(parcHashMap_IsValid(instance), "Expected parcHashMap_Create to result in an invalid instance.");
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_AssertValid)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+ parcHashMap_Put(instance, key, value);
+ parcHashMap_AssertValid(instance);
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_ToJSON)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+ parcHashMap_Put(instance, key, value);
+
+ PARCJSON *json = parcHashMap_ToJSON(instance);
+
+ parcJSON_Release(&json);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(ObjectContract, parcHashMap_ToString)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+ parcHashMap_Put(instance, key, value);
+
+ char *string = parcHashMap_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcHashMap_ToString");
+
+ parcMemory_Deallocate(&string);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Put);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_PutN);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Put_Replace);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Get_NoValue);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Contains_True);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Contains_False);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Remove);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Remove_False);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_Resize);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_GetClusteringNumber);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_CreateValueIterator);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_CreateValueIterator_HasNext);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_CreateValueIterator_Next);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_KeyIterator);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_KeyIterator_HasNext);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_KeyIterator_Next);
+ LONGBOW_RUN_TEST_CASE(Global, parcHashMap_KeyIterator_Remove);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_Put)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ //size_t keyReferences = parcObject_GetReferenceCount(key);
+ size_t valueReferences = parcObject_GetReferenceCount(value);
+
+ parcHashMap_Put(instance, key, value);
+ //M.S. Put() now results in a copy of the key.
+ //assertTrue(keyReferences + 1 == parcObject_GetReferenceCount(key), "Expected key reference to be incremented by 1.");
+ assertTrue(valueReferences + 1 == parcObject_GetReferenceCount(value), "Expected value reference to be incremented by 1.");
+
+ PARCBuffer *actual = (PARCBuffer *) parcHashMap_Get(instance, key);
+
+ assertTrue(parcBuffer_Equals(value, actual), "Expected value was not returned from Get");
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+typedef struct {
+ int64_t number;
+} _Int;
+
+static char *
+_int_toString(const _Int *anInt)
+{
+ char *result = parcMemory_AllocateAndClear(22);
+ sprintf(result, "%" PRIi64 "", anInt->number);
+ return result;
+}
+
+static PARCHashCode
+_int_hashCode(const _Int *anInt)
+{
+ PARCHashCode result = anInt->number;
+
+ return result;
+}
+
+parcObject_ExtendPARCObject(_Int, NULL, NULL, _int_toString, NULL, NULL, _int_hashCode, NULL);
+
+parcObject_ImplementRelease(_int, _Int);
+
+static _Int *
+_int_Create(int64_t anInt)
+{
+ _Int *_int = parcObject_CreateInstance(_Int);
+
+ if (_int != NULL) {
+ _int->number = anInt;
+ }
+
+ return _int;
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_GetClusteringNumber)
+{
+ size_t minimumSize = 100;
+ PARCHashMap *instance = parcHashMap_CreateCapacity(minimumSize);
+
+ double maxLoadFactor = instance->maxLoadFactor;
+
+ // Load a hash map up to its load-factor
+ size_t testRunSize = minimumSize * maxLoadFactor - 20;
+ srand(time(NULL));
+ for (int i = 0; i < testRunSize; ++i) {
+ _Int *key = _int_Create(rand());
+ PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(value, 1000 + i);
+ parcHashMap_Put(instance, key, value);
+ parcBuffer_Release(&value);
+ _int_Release(&key);
+ }
+
+ double currentClusteringNumber = parcHashMap_GetClusteringNumber(instance);
+
+ if (currentClusteringNumber < 0.5) {
+ testWarn("Oddly low clustering number detected.");
+ }
+
+ if (currentClusteringNumber > 1.5) {
+ testWarn("Oddly high clustering number detected.");
+ }
+
+ // This will load up one bucket
+ for (int i = 0; i < 20; ++i) {
+ _Int *key = _int_Create(1 + (100 * i));
+ PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(value, 10 + i);
+ parcHashMap_Put(instance, key, value);
+ parcBuffer_Release(&value);
+ _int_Release(&key);
+ }
+
+ currentClusteringNumber = parcHashMap_GetClusteringNumber(instance);
+
+ parcHashMap_Release(&instance);
+
+ if (currentClusteringNumber < 2.9) {
+ testWarn("Oddly low clustering number detected.");
+ }
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_Resize)
+{
+ size_t initialSize = 8;
+ PARCHashMap *instance = parcHashMap_CreateCapacity(initialSize);
+
+ PARCBuffer *key = parcBuffer_Allocate(sizeof(uint32_t));
+ PARCBuffer *value42 = parcBuffer_WrapCString("value42");
+ double maxLoadFactor = instance->maxLoadFactor;
+
+ // Load a hash map up to its load-factor
+ size_t testRunSize = initialSize * maxLoadFactor;
+ for (uint32_t i = 0; i < testRunSize; ++i) {
+ parcBuffer_PutUint32(key, i);
+ PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(value, 1000 + i);
+ parcHashMap_Put(instance, parcBuffer_Flip(key), value);
+ parcBuffer_Release(&value);
+ }
+ assertTrue(parcHashMap_Size(instance) == testRunSize, "Expect the size to be %zu", testRunSize);
+ assertTrue(instance->capacity == initialSize, "Expect to have the original capacity");
+
+ // Test for expected values
+ for (uint32_t i = 0; i < testRunSize; ++i) {
+ parcBuffer_PutUint32(key, i);
+ PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(value, 1000 + i);
+ const PARCBuffer *storedValue = parcHashMap_Get(instance, parcBuffer_Flip(key));
+ assertTrue(parcBuffer_Equals(value, storedValue), "Expect looked up values to match");
+ parcBuffer_Release(&value);
+ }
+
+ // Add one more item to the the hash map, this should trigger an expansion
+ parcBuffer_PutUint32(key, 42);
+ parcHashMap_Put(instance, parcBuffer_Flip(key), value42);
+ assertTrue(parcHashMap_Size(instance) == testRunSize + 1, "Expect the size to be %zu", testRunSize);
+ assertTrue(instance->capacity == 2 * initialSize, "Expect to have the original capacity");
+
+ // Re-test value look ups to make sure the new hash map still maps correctly
+ for (uint32_t i = 0; i < testRunSize; ++i) {
+ parcBuffer_PutUint32(key, i);
+ PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(value, 1000 + i);
+ const PARCBuffer *storedValue = parcHashMap_Get(instance, parcBuffer_Flip(key));
+ assertTrue(parcBuffer_Equals(value, storedValue), "Expect looked up values to match");
+ parcBuffer_Release(&value);
+ }
+ double averageBucketSize = parcHashMap_GetClusteringNumber(instance);
+ parcBuffer_PutUint32(key, 42);
+ const PARCBuffer *storedValue = parcHashMap_Get(instance, parcBuffer_Flip(key));
+ assertTrue(parcBuffer_Equals(value42, storedValue), "Expect to get back value42");
+ parcBuffer_Release(&value42);
+ assertTrue(parcHashMap_GetClusteringNumber(instance) <= averageBucketSize,
+ "Expect the average bucket size to be less then it was");
+
+ // Now test multiple expansions to make sure they happened are result in a valid hash map
+ size_t testCapacity = 1024;
+ // If we load up to (maxLoadFactor * testCapacity) + 1, the capacity should expand to 2 * testCapacity
+ testRunSize = (testCapacity * maxLoadFactor) + 1;
+ for (uint32_t i = 0; i < testRunSize; ++i) {
+ parcBuffer_PutUint32(key, i);
+ PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(value, 1000 + i);
+ parcHashMap_Put(instance, parcBuffer_Flip(key), value);
+ parcBuffer_Release(&value);
+ if (i == (testRunSize - 2)) {
+ averageBucketSize = parcHashMap_GetClusteringNumber(instance);
+ }
+ }
+ assertTrue(instance->capacity == (2 * testCapacity),
+ "Expect capacity to be %zu got %zu", (2 * testCapacity), instance->capacity);
+ assertTrue(parcHashMap_GetClusteringNumber(instance) < averageBucketSize,
+ "Expect the average bucket size to be less then it was");
+
+ // Now test multiple contractions.
+ // If we remove all elements from index "smallSize" (eg. 8) up we will be left with a map of size smallSize,
+ // the map capacity should be contracting and, because the minimum load factor is 0.25 and the contraction
+ // is a divide by 2, the last contraction should be from capacity of "smallSize * 4" (32) to one
+ // of "smallSize * 2" (16) when size goes from "smallSize +1" (9) to "smallSize" (8).
+ //
+ size_t smallSize = 8;
+ for (uint32_t i = smallSize; i < testRunSize; ++i) {
+ parcBuffer_PutUint32(key, i);
+ parcBuffer_Flip(key);
+ PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(value, 1000 + i);
+ const PARCBuffer *storedValue = parcHashMap_Get(instance, key);
+ assertTrue(parcBuffer_Equals(value, storedValue), "Expect looked up values to match");
+ parcBuffer_Release(&value);
+
+ assertTrue(parcHashMap_Remove(instance, key), "Expect Remove to succeed");
+ }
+ assertTrue(instance->size == smallSize,
+ "Expect the hash map to have size %zu, got %zu", smallSize, instance->size)
+ assertTrue(instance->capacity == (smallSize * 2),
+ "Expect capacity to be %zu, got %zu", (smallSize * 2), instance->capacity);
+
+ // Re-test value look ups to make sure the new hash map still maps correctly
+ for (uint32_t i = 0; i < smallSize; ++i) {
+ parcBuffer_PutUint32(key, i);
+ PARCBuffer *value = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(value, 1000 + i);
+ const PARCBuffer *storedValue = parcHashMap_Get(instance, parcBuffer_Flip(key));
+ assertTrue(parcBuffer_Equals(value, storedValue), "Expect looked up values to match");
+ parcBuffer_Release(&value);
+ }
+
+ parcBuffer_Release(&key);
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_PutN)
+{
+ size_t testRunSize = 100;
+
+ PARCHashMap *instance = parcHashMap_CreateCapacity(testRunSize);
+
+ PARCBuffer *key = parcBuffer_Allocate(sizeof(uint32_t));
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+ PARCBuffer *value42 = parcBuffer_WrapCString("value42");
+ for (uint32_t i = 0; i < testRunSize * 2; ++i) {
+ parcBuffer_PutUint32(key, i);
+ parcHashMap_Put(instance, parcBuffer_Flip(key), value);
+ if (i == 42) {
+ parcHashMap_Put(instance, key, value42);
+ }
+ }
+
+ parcBuffer_PutUint32(key, 42);
+ PARCBuffer *actual = (PARCBuffer *) parcHashMap_Get(instance, parcBuffer_Flip(key));
+ assertTrue(parcBuffer_Equals(value42, actual), "Expect to get back value42");
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+ parcBuffer_Release(&value42);
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_Put_Replace)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value1 = parcBuffer_WrapCString("value1");
+ PARCBuffer *value2 = parcBuffer_WrapCString("value2");
+
+ parcHashMap_Put(instance, key, value1);
+
+ parcHashMap_Put(instance, key, value2);
+
+ PARCBuffer *actual = (PARCBuffer *) parcHashMap_Get(instance, key);
+
+ assertTrue(parcBuffer_Equals(value2, actual), "Expected value was not returned from Get");
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value1);
+ parcBuffer_Release(&value2);
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_Get_NoValue)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+
+ PARCBuffer *actual = (PARCBuffer *) parcHashMap_Get(instance, key);
+
+ assertNull(actual, "Expected parcHashMap_Get to return NULL for non-existent key.");
+
+ parcBuffer_Release(&key);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_Contains_True)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ parcHashMap_Put(instance, key, value);
+
+ bool actual = parcHashMap_Contains(instance, key);
+
+ assertTrue(actual, "Expected parcHashMap_Contains to return true");
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_Contains_False)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+
+ bool actual = parcHashMap_Contains(instance, key);
+
+ assertFalse(actual, "Expected parcHashMap_Contains to return NULL for non-existent key.");
+
+ parcBuffer_Release(&key);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_Remove)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ parcHashMap_Put(instance, key, value);
+
+ bool actual = parcHashMap_Remove(instance, key);
+
+ assertTrue(actual, "Expected parcHashMap_Remove to return true.");
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_Remove_False)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *key2 = parcBuffer_WrapCString("key2");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ parcHashMap_Put(instance, key, value);
+
+ bool actual = parcHashMap_Remove(instance, key2);
+
+ assertFalse(actual, "Expected parcHashMap_Remove to return false.");
+
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&key2);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_CreateValueIterator)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ parcHashMap_Put(instance, key, value);
+
+ PARCIterator *iterator = parcHashMap_CreateValueIterator(instance);
+
+ assertNotNull(iterator, "Expected parcHashMap_ValueIterator to return non-null result");
+
+ parcIterator_Release(&iterator);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_CreateValueIterator_HasNext)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ parcHashMap_Put(instance, key, value);
+
+ PARCIterator *iterator = parcHashMap_CreateValueIterator(instance);
+
+ assertTrue(parcIterator_HasNext(iterator), "Expected parcIterator_HasNext to return true");
+
+ parcIterator_Release(&iterator);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_CreateValueIterator_Next)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key1 = parcBuffer_WrapCString("key1");
+ PARCBuffer *value1 = parcBuffer_WrapCString("1");
+ PARCBuffer *key2 = parcBuffer_WrapCString("key2");
+ PARCBuffer *value2 = parcBuffer_WrapCString("2");
+ PARCBuffer *key3 = parcBuffer_WrapCString("key3");
+ PARCBuffer *value3 = parcBuffer_WrapCString("3");
+ PARCBuffer *key4 = parcBuffer_WrapCString("key4");
+ PARCBuffer *value4 = parcBuffer_WrapCString("4");
+
+ parcHashMap_Put(instance, key1, value1);
+ parcHashMap_Put(instance, key2, value2);
+ parcHashMap_Put(instance, key3, value3);
+ parcHashMap_Put(instance, key4, value4);
+
+ PARCIterator *iterator = parcHashMap_CreateValueIterator(instance);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCBuffer *actual = parcIterator_Next(iterator);
+ assertNotNull(actual, "Expected parcIterator_Next to return non-null");
+ assertTrue(parcBuffer_Remaining(actual) > 0, "The same value appeared more than once in the iteration");
+ parcBuffer_SetPosition(actual, parcBuffer_Limit(actual));
+ }
+ parcIterator_Release(&iterator);
+
+ parcBuffer_Release(&key1);
+ parcBuffer_Release(&value1);
+ parcBuffer_Release(&key2);
+ parcBuffer_Release(&value2);
+ parcBuffer_Release(&key3);
+ parcBuffer_Release(&value3);
+ parcBuffer_Release(&key4);
+ parcBuffer_Release(&value4);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_KeyIterator)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ parcHashMap_Put(instance, key, value);
+
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator(instance);
+
+ assertNotNull(iterator, "Expected parcHashMap_KeyIterator to return non-null result");
+
+ parcIterator_Release(&iterator);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_KeyIterator_HasNext)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ parcHashMap_Put(instance, key, value);
+
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator(instance);
+
+ assertTrue(parcIterator_HasNext(iterator), "Expected parcIterator_HasNext to return true");
+
+ parcIterator_Release(&iterator);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_KeyIterator_Next)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key1 = parcBuffer_WrapCString("key1");
+ PARCBuffer *value1 = parcBuffer_WrapCString("1");
+ PARCBuffer *key2 = parcBuffer_WrapCString("key2");
+ PARCBuffer *value2 = parcBuffer_WrapCString("2");
+ PARCBuffer *key3 = parcBuffer_WrapCString("key3");
+ PARCBuffer *value3 = parcBuffer_WrapCString("3");
+ PARCBuffer *key4 = parcBuffer_WrapCString("key4");
+ PARCBuffer *value4 = parcBuffer_WrapCString("4");
+
+ parcHashMap_Put(instance, key1, value1);
+ parcHashMap_Put(instance, key2, value2);
+ parcHashMap_Put(instance, key3, value3);
+ parcHashMap_Put(instance, key4, value4);
+
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator(instance);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCBuffer *actual = parcIterator_Next(iterator);
+ assertNotNull(actual, "Expected parcIterator_Next to return non-null");
+ assertTrue(parcBuffer_Remaining(actual) > 0, "The same value appeared more than once in the iteration");
+ parcBuffer_SetPosition(actual, parcBuffer_Limit(actual));
+ }
+ parcIterator_Release(&iterator);
+
+ parcBuffer_Release(&key1);
+ parcBuffer_Release(&value1);
+ parcBuffer_Release(&key2);
+ parcBuffer_Release(&value2);
+ parcBuffer_Release(&key3);
+ parcBuffer_Release(&value3);
+ parcBuffer_Release(&key4);
+ parcBuffer_Release(&value4);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcHashMap_KeyIterator_Remove)
+{
+ PARCHashMap *instance = parcHashMap_Create();
+
+ PARCBuffer *key1 = parcBuffer_WrapCString("key1");
+ PARCBuffer *value1 = parcBuffer_WrapCString("1");
+ PARCBuffer *key2 = parcBuffer_WrapCString("key2");
+ PARCBuffer *value2 = parcBuffer_WrapCString("2");
+ PARCBuffer *key3 = parcBuffer_WrapCString("key3");
+ PARCBuffer *value3 = parcBuffer_WrapCString("3");
+ PARCBuffer *key4 = parcBuffer_WrapCString("key4");
+ PARCBuffer *value4 = parcBuffer_WrapCString("4");
+
+ parcHashMap_Put(instance, key1, value1);
+ parcHashMap_Put(instance, key2, value2);
+ parcHashMap_Put(instance, key3, value3);
+ parcHashMap_Put(instance, key4, value4);
+
+ assertTrue(parcHashMap_Size(instance) == 4, "Expected 4, actual %zd", parcHashMap_Size(instance));
+ PARCIterator *iterator = parcHashMap_CreateKeyIterator(instance);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCBuffer *key = parcBuffer_Acquire(parcIterator_Next(iterator));
+ parcIterator_Remove(iterator);
+ assertNull(parcHashMap_Get(instance, key), "Expected deleted entry to not be gettable.");
+ parcBuffer_Release(&key);
+ }
+ parcIterator_Release(&iterator);
+
+ assertTrue(parcHashMap_Size(instance) == 0, "Expected 0, actual %zd", parcHashMap_Size(instance));
+ parcBuffer_Release(&key1);
+ parcBuffer_Release(&value1);
+ parcBuffer_Release(&key2);
+ parcBuffer_Release(&value2);
+ parcBuffer_Release(&key3);
+ parcBuffer_Release(&value3);
+ parcBuffer_Release(&key4);
+ parcBuffer_Release(&value4);
+
+ parcHashMap_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, parcHashMapEntry);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Static, parcHashMapEntry)
+{
+ PARCBuffer *key = parcBuffer_WrapCString("key1");
+ PARCBuffer *value = parcBuffer_WrapCString("value1");
+
+ _PARCHashMapEntry *instance = _parcHashMapEntry_Create(key, value);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ _parcHashMapEntry_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_HashMap);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_InputStream.c b/libparc/parc/algol/test/test_parc_InputStream.c
new file mode 100755
index 00000000..46d47862
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_InputStream.c
@@ -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.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_InputStream.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_InputStream)
+{
+ // 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(parc_InputStream)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_InputStream)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcInputStream);
+ LONGBOW_RUN_TEST_CASE(Global, parcInputStream_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcInputStream_Read);
+ LONGBOW_RUN_TEST_CASE(Global, parcInputStream_Release);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcInputStream)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcInputStream_Acquire)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcInputStream_Read)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcInputStream_Release)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, parcInputStream_Finalize);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, parcInputStream_Finalize)
+{
+ testUnimplemented("");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_InputStream);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Iterator.c b/libparc/parc/algol/test/test_parc_Iterator.c
new file mode 100644
index 00000000..d5778721
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Iterator.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_Iterator.c"
+
+#include <inttypes.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/testing/parc_MemoryTesting.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_Iterator)
+{
+ // 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(parc_Iterator)
+{
+ 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_Iterator)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, parcIterator_CreateAcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s", longBowTestCase_GetName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static uint64_t _state;
+
+static void *
+init(PARCObject *object __attribute__((unused)))
+{
+ _state = 0;
+ return &_state;
+}
+
+static bool
+hasNext(PARCObject *object __attribute__((unused)), void *state)
+{
+ uint64_t *value = (uint64_t *) state;
+ return (*value < 5);
+}
+
+static void *
+next(PARCObject *object __attribute__((unused)), void *state)
+{
+ uint64_t *value = (uint64_t *) state;
+
+ (*value)++;
+ return state;
+}
+
+static void
+removex(PARCObject *object __attribute__((unused)), void **state)
+{
+}
+
+static void *
+getElement(PARCObject *object __attribute__((unused)), void *state)
+{
+ uint64_t *value = (uint64_t *) state;
+ return (void *) *value;
+}
+
+static void
+fini(PARCObject *object __attribute__((unused)), void *state __attribute__((unused)))
+{
+}
+
+static void
+assertValid(const void *state __attribute__((unused)))
+{
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, parcIterator_CreateAcquireRelease)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+
+ PARCIterator *iterator = parcIterator_Create(buffer, init, hasNext, next, removex, getElement, fini, assertValid);
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcIterator_Acquire, iterator);
+ parcBuffer_Release(&buffer);
+ parcIterator_Release(&iterator);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcIterator_HasNext);
+ LONGBOW_RUN_TEST_CASE(Global, parcIterator_Next);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true;
+ if (leaked) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcIterator_HasNext)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+
+ PARCIterator *iterator = parcIterator_Create(buffer, init, hasNext, next, removex, getElement, fini, assertValid);
+
+ while (parcIterator_HasNext(iterator)) {
+ uint64_t value = (uint64_t) parcIterator_Next(iterator);
+ printf("%" PRIu64 "\n", value);
+ }
+ parcBuffer_Release(&buffer);
+ parcIterator_Release(&iterator);
+}
+
+LONGBOW_TEST_CASE(Global, parcIterator_Next)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(1);
+
+ PARCIterator *iterator = parcIterator_Create(buffer, init, hasNext, next, removex, getElement, fini, assertValid);
+
+ while (parcIterator_HasNext(iterator)) {
+ uint64_t value = (uint64_t) parcIterator_Next(iterator);
+ printf("%" PRIu64 "\n", value);
+ }
+ parcBuffer_Release(&buffer);
+ parcIterator_Release(&iterator);
+}
+
+LONGBOW_TEST_CASE(Local, _finalize)
+{
+ testUnimplemented("");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Iterator);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_JSON.c b/libparc/parc/algol/test/test_parc_JSON.c
new file mode 100644
index 00000000..d1825319
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_JSON.c
@@ -0,0 +1,690 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_JSON.c"
+#include "../parc_JSONPair.c"
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include <LongBow/unit-test.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+
+#include "../parc_List.h"
+#include "../parc_ArrayList.h"
+#include "../parc_SafeMemory.h"
+#include "../parc_Memory.h"
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_JSON)
+{
+ // 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(Static);
+ LONGBOW_RUN_TEST_FIXTURE(JSON);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_JSON)
+{
+ 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_JSON)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(JSON)
+{
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_CreateRelease);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_Equals);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_HashCode);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_Copy);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_Add);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetMembers);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetPairByName);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetValueByName);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetPairByIndex);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetValueByIndex);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_BuildString);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_ToString);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_ToCompactString);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetByPath);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetByPath_BadArrayIndex);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_GetByPath_DeadEndPath);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_ParseString);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_ParseBuffer_WithExcess);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_Display);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddString);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddObject);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddInteger);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddBoolean);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddArray);
+ LONGBOW_RUN_TEST_CASE(JSON, parcJSON_AddValue);
+}
+
+typedef struct {
+ PARCJSON *json;
+ char *expected;
+ char *compactExpected;
+} TestData;
+
+LONGBOW_TEST_FIXTURE_SETUP(JSON)
+{
+ TestData *data = parcMemory_Allocate(sizeof(TestData));
+
+ char *temp = "{ \"string\" : \"foo\\/bar\", \"null\" : null, \"true\" : true, \"false\" : false, \"integer\" : 31415, \"float\" : 3.141500, \"json\" : { \"string\" : \"foo\\/bar\" }, \"array\" : [ null, false, true, 31415, \"string\", [ null, false, true, 31415, \"string\" ], { } ] }";
+ data->expected = parcMemory_StringDuplicate(temp, strlen(temp));
+
+ temp = "{\"string\":\"foo/bar\",\"null\":null,\"true\":true,\"false\":false,\"integer\":31415,\"float\":3.141500,\"json\":{\"string\":\"foo/bar\"},\"array\":[null,false,true,31415,\"string\",[null,false,true,31415,\"string\"],{}]}";
+ data->compactExpected = parcMemory_StringDuplicate(temp, strlen(temp));
+
+ data->json = parcJSON_ParseString(temp);
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(JSON)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcJSON_Release(&data->json);
+ parcMemory_Deallocate(&data->expected);
+ parcMemory_Deallocate(&data->compactExpected);
+
+ parcMemory_Deallocate(&data);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+LONGBOW_TEST_CASE(JSON, parcJSON_CreateRelease)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ parcJSON_Release(&json);
+ assertNull(json, "Expected the NULL pointer side-effect of Release.");
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_Copy)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCJSON *copy = parcJSON_Copy(data->json);
+
+ assertTrue(parcJSON_Equals(data->json, copy), "Expect copy to equal original");
+
+ parcJSON_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_HashCode)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCHashCode expected = parcHashCode_Hash((uint8_t *) data->compactExpected, strlen(data->compactExpected));
+
+ PARCHashCode hashCode = parcJSON_HashCode(data->json);
+
+ assertTrue(hashCode == expected, "Expect correct hash code");
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_Add)
+{
+ PARCJSON *json = parcJSON_Create();
+ {
+ PARCBuffer *string = parcBuffer_WrapCString("string");
+ PARCJSONValue *stringValue = parcJSONValue_CreateFromString(string);
+ PARCBuffer *stringName = parcBuffer_WrapCString("string");
+ PARCJSONPair *pair = parcJSONPair_Create(stringName, stringValue);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&stringName);
+ parcJSONValue_Release(&stringValue);
+ parcBuffer_Release(&string);
+ }
+ {
+ PARCBuffer *name = parcBuffer_WrapCString("null");
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ PARCJSONPair *pair = parcJSONPair_Create(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&value);
+ }
+ {
+ PARCBuffer *name = parcBuffer_WrapCString("true");
+ PARCJSONValue *value = parcJSONValue_CreateFromBoolean(true);
+ PARCJSONPair *pair = parcJSONPair_Create(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&value);
+ }
+ {
+ PARCBuffer *name = parcBuffer_WrapCString("false");
+ PARCJSONValue *value = parcJSONValue_CreateFromBoolean(false);
+ PARCJSONPair *pair = parcJSONPair_Create(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&value);
+ }
+ {
+ PARCBuffer *name = parcBuffer_WrapCString("integer");
+ PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415);
+ PARCJSONPair *pair = parcJSONPair_Create(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&value);
+ }
+ {
+ PARCBuffer *name = parcBuffer_WrapCString("float");
+ PARCJSONValue *value = parcJSONValue_CreateFromFloat(3.1415);
+ PARCJSONPair *pair = parcJSONPair_Create(name, value);
+ parcJSON_AddPair(json, pair);
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&value);
+ }
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_GetMembers)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ char *s = parcJSON_ToString(data->json);
+ parcMemory_Deallocate((void **) &s);
+
+ PARCList *members = parcJSON_GetMembers(data->json);
+ assertTrue(parcList_Size(members) == 8, "Expected 8, actual %zd", parcList_Size(members));
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_GetPairByName)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ int expected = 31415;
+ const PARCJSONPair *pair = parcJSON_GetPairByName(data->json, "integer");
+
+ PARCBuffer *name = parcJSONPair_GetName(pair);
+ PARCJSONValue *value = parcJSONPair_GetValue(pair);
+
+ int64_t actual = parcJSONValue_GetInteger(value);
+
+ PARCBuffer *expectedName = parcBuffer_WrapCString("integer");
+
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'integer', actual '%s'", (char *) parcBuffer_ToString(name));
+
+ assertTrue(expected == actual, "Expected %d, actual %" PRIi64 "", expected, actual);
+
+ parcBuffer_Release(&expectedName);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_GetValueByName)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ int expected = 31415;
+ const PARCJSONValue *value = parcJSON_GetValueByName(data->json, "integer");
+
+ int64_t actual = parcJSONValue_GetInteger(value);
+
+ PARCBuffer *expectedName = parcBuffer_WrapCString("integer");
+
+ assertTrue(expected == actual, "Expected %d, actual %" PRIi64 "", expected, actual);
+
+ parcBuffer_Release(&expectedName);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_GetPairByIndex)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCJSONPair *pair = parcJSON_GetPairByIndex(data->json, 0);
+ PARCBuffer *name = parcJSONPair_GetName(pair);
+ PARCBuffer *expectedName = parcBuffer_WrapCString("string");
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'string', actual '%s'", (char *) parcBuffer_ToString(name));
+ parcBuffer_Release(&expectedName);
+
+ pair = parcJSON_GetPairByIndex(data->json, 1);
+ name = parcJSONPair_GetName(pair);
+ expectedName = parcBuffer_WrapCString("null");
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'null', actual '%s'", (char *) parcBuffer_ToString(name));
+ parcBuffer_Release(&expectedName);
+
+ pair = parcJSON_GetPairByIndex(data->json, 2);
+ name = parcJSONPair_GetName(pair);
+ expectedName = parcBuffer_WrapCString("true");
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'true', actual '%s'", (char *) parcBuffer_ToString(name));
+ parcBuffer_Release(&expectedName);
+
+ pair = parcJSON_GetPairByIndex(data->json, 3);
+ name = parcJSONPair_GetName(pair);
+ expectedName = parcBuffer_WrapCString("false");
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'false', actual '%s'", (char *) parcBuffer_ToString(name));
+ parcBuffer_Release(&expectedName);
+
+ pair = parcJSON_GetPairByIndex(data->json, 4);
+ name = parcJSONPair_GetName(pair);
+ expectedName = parcBuffer_WrapCString("integer");
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'integer', actual '%s'", (char *) parcBuffer_ToString(name));
+ parcBuffer_Release(&expectedName);
+
+ pair = parcJSON_GetPairByIndex(data->json, 5);
+ name = parcJSONPair_GetName(pair);
+ expectedName = parcBuffer_WrapCString("float");
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'float', actual '%s'", (char *) parcBuffer_ToString(name));
+ parcBuffer_Release(&expectedName);
+
+ pair = parcJSON_GetPairByIndex(data->json, 6);
+ name = parcJSONPair_GetName(pair);
+ expectedName = parcBuffer_WrapCString("json");
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'json', actual '%s'", (char *) parcBuffer_ToString(name));
+ parcBuffer_Release(&expectedName);
+
+ pair = parcJSON_GetPairByIndex(data->json, 7);
+ name = parcJSONPair_GetName(pair);
+ expectedName = parcBuffer_WrapCString("array");
+ assertTrue(parcBuffer_Equals(expectedName, name),
+ "Expected 'array', actual '%s'", (char *) parcBuffer_ToString(name));
+ parcBuffer_Release(&expectedName);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_GetValueByIndex)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCJSONValue *value = parcJSON_GetValueByIndex(data->json, 0);
+ assertTrue(parcJSONValue_IsString(value),
+ "Expected value to be type string");
+
+ value = parcJSON_GetValueByIndex(data->json, 1);
+ assertTrue(parcJSONValue_IsNull(value),
+ "Expected value to be type string");
+
+ value = parcJSON_GetValueByIndex(data->json, 2);
+ assertTrue(parcJSONValue_IsBoolean(value),
+ "Expected value to be type string");
+
+ value = parcJSON_GetValueByIndex(data->json, 3);
+ assertTrue(parcJSONValue_IsBoolean(value),
+ "Expected value to be type string");
+
+ value = parcJSON_GetValueByIndex(data->json, 4);
+ assertTrue(parcJSONValue_IsNumber(value),
+ "Expected value to be type string");
+
+ value = parcJSON_GetValueByIndex(data->json, 5);
+ assertTrue(parcJSONValue_IsNumber(value),
+ "Expected value to be type string");
+
+ value = parcJSON_GetValueByIndex(data->json, 6);
+ assertTrue(parcJSONValue_IsJSON(value),
+ "Expected value to be type string");
+
+ value = parcJSON_GetValueByIndex(data->json, 7);
+ assertTrue(parcJSONValue_IsArray(value),
+ "Expected value to be type string");
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_BuildString)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcJSON_BuildString(data->json, composer, false);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ assertTrue(strcmp(data->expected, actual) == 0, "Expected %s, actual %s", data->expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ composer = parcBufferComposer_Create();
+ parcJSON_BuildString(data->json, composer, true);
+
+ tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ assertTrue(strcmp(data->compactExpected, actual) == 0, "Expected %s, actual %s", data->compactExpected, actual);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_ToString)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ char *actual = parcJSON_ToString(data->json);
+ assertTrue(strcmp(data->expected, actual) == 0, "Expected %s, actual %s", data->expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_ToCompactString)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ char *actual = parcJSON_ToCompactString(data->json);
+ assertTrue(strcmp(data->compactExpected, actual) == 0, "Expected %s, actual %s", data->expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_GetByPath)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCJSON *json = data->json;
+
+ char *s = parcJSON_ToString(json);
+ printf("%s\n", s);
+ parcMemory_Deallocate((void **) &s);
+
+ const PARCJSONValue *value = parcJSON_GetByPath(json, "/string");
+ assertTrue(parcJSONValue_IsString(value), "Expected /string to be a string type.");
+ value = parcJSON_GetByPath(json, "/null");
+ assertTrue(parcJSONValue_IsNull(value), "Expected /null to be a null type.");
+ value = parcJSON_GetByPath(json, "/true");
+ assertTrue(parcJSONValue_IsBoolean(value), "Expected /true to be a boolean type.");
+ value = parcJSON_GetByPath(json, "/integer");
+ assertTrue(parcJSONValue_IsNumber(value), "Expected /integer to be a number type.");
+ value = parcJSON_GetByPath(json, "/float");
+ assertTrue(parcJSONValue_IsNumber(value), "Expected /float to be a number type.");
+ value = parcJSON_GetByPath(json, "/array");
+ assertTrue(parcJSONValue_IsArray(value), "Expected /array to be an array type.");
+ value = parcJSON_GetByPath(json, "/nonexistent");
+ assertNull(value, "Expected /nonexistent to be NULL");
+
+ value = parcJSON_GetByPath(json, "/array/1");
+ assertTrue(parcJSONValue_IsBoolean(value), "Expected /array/0 to be a boolean type.");
+
+ value = parcJSON_GetByPath(json, "/array/5");
+ assertTrue(parcJSONValue_IsArray(value), "Expected /array/5 to be an array type.");
+
+ assertNotNull(value, "Expected non-null pair");
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_GetByPath_BadArrayIndex)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ const PARCJSONValue *value = parcJSON_GetByPath(data->json, "/array/100");
+ assertNull(value, "Expected null value return from parcJSON_GetByPath");
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_GetByPath_DeadEndPath)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ const PARCJSONValue *value = parcJSON_GetByPath(data->json, "/string/foo");
+ assertNull(value, "Expected null value return from parcJSON_GetByPath");
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_Equals)
+{
+ PARCJSON *x = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+ PARCJSON *y = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+ PARCJSON *z = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+
+ PARCJSON *notEqual1 = parcJSON_ParseString("{ \"string\" : \"string\" }");
+
+ PARCJSON *notEqual2 = parcJSON_ParseString("{ \"string\" : \"xyzzy\", \"integer\" : 1 }");
+
+ parcObjectTesting_AssertEqualsFunction(parcJSON_Equals, x, y, z, notEqual1, notEqual2);
+
+ parcJSON_Release(&x);
+ parcJSON_Release(&y);
+ parcJSON_Release(&z);
+ parcJSON_Release(&notEqual1);
+ parcJSON_Release(&notEqual2);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_Display)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcJSON_Display(data->json, 0);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_ParseString)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCJSON *json = parcJSON_ParseString(data->expected);
+
+ char *actual = parcJSON_ToString(json);
+
+ assertTrue(strcmp(data->expected, actual) == 0, "Expected %s, actual %s", data->expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_ParseBuffer_WithExcess)
+{
+ char *string = "{ \"string\" : \"string\", \"null\" : null, \"true\" : true, \"false\" : false, \"integer\" : 31415, \"float\" : 3.141500, \"array\" : [ null, false, true, 31415, \"string\", [ null, false, true, 31415, \"string\" ], { } ] }Xhowdy";
+ PARCBuffer *buffer = parcBuffer_WrapCString((char *) string);
+
+ PARCJSON *json = parcJSON_ParseBuffer(buffer);
+
+ char actual = parcBuffer_GetUint8(buffer);
+ assertTrue(actual == 'X', "Expected buffer position to point to X, actual %x", actual);
+
+ parcBuffer_Release(&buffer);
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_AddString)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ char *expectedName = "string";
+ char *expectedValue = "value";
+
+ parcJSON_AddString(json, expectedName, expectedValue);
+
+ const PARCJSONPair *pair = parcJSON_GetPairByName(json, "string");
+ PARCBuffer *actualName = parcJSONPair_GetName(pair);
+ PARCJSONValue *actualValue = parcJSONPair_GetValue(pair);
+
+ assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0,
+ "Expected name %s, actual %s",
+ expectedName,
+ parcBuffer_ToString(actualName));
+ assertTrue(strcmp(expectedValue, parcBuffer_Overlay(parcJSONValue_GetString(actualValue), 0)) == 0,
+ "Expected value %s, actual %s",
+ expectedValue,
+ parcJSONValue_ToString(actualValue));
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_AddObject)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ PARCJSON *expectedValue = parcJSON_ParseString("{ \"string\" : \"xyzzy\" }");
+ parcJSON_AddObject(json, "object", expectedValue);
+
+ char *expectedName = "object";
+ const PARCJSONPair *pair = parcJSON_GetPairByName(json, expectedName);
+
+ PARCBuffer *actualName = parcJSONPair_GetName(pair);
+ PARCJSONValue *actualValue = parcJSONPair_GetValue(pair);
+
+ assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0,
+ "Expected name %s, actual %s", expectedName, (char *) parcBuffer_ToString(actualName));
+
+ assertTrue(parcJSON_Equals(expectedValue, parcJSONValue_GetJSON(actualValue)),
+ "Expected value did not match the actual value.");
+
+ parcJSON_Release(&expectedValue);
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_AddInteger)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ char *expectedName = "integer";
+ uint64_t expectedValue = 12345;
+
+ parcJSON_AddInteger(json, expectedName, expectedValue);
+
+ const PARCJSONPair *pair = parcJSON_GetPairByName(json, expectedName);
+
+ PARCBuffer *actualName = parcJSONPair_GetName(pair);
+ PARCJSONValue *actualValue = parcJSONPair_GetValue(pair);
+
+ assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0,
+ "Expected name %s, actual %s", expectedName, (char *) parcBuffer_ToString(actualName));
+
+ assertTrue(expectedValue == parcJSONValue_GetInteger(actualValue),
+ "Expected %" PRIi64 "d actual %" PRIi64 "d", expectedValue, parcJSONValue_GetInteger(actualValue));
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_AddBoolean)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ char *expectedName = "boolean";
+ bool expectedValue = true;
+
+ parcJSON_AddBoolean(json, expectedName, expectedValue);
+
+ const PARCJSONPair *pair = parcJSON_GetPairByName(json, expectedName);
+
+ PARCBuffer *actualName = parcJSONPair_GetName(pair);
+ PARCJSONValue *actualValue = parcJSONPair_GetValue(pair);
+
+ assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0,
+ "Expected name %s, actual %s", expectedName, (char *) parcBuffer_ToString(actualName));
+
+ assertTrue(expectedValue == parcJSONValue_GetBoolean(actualValue),
+ "Expected %d actual %d", expectedValue, parcJSONValue_GetBoolean(actualValue));
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_AddArray)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ char *expectedName = "array";
+
+ PARCJSONArray *array = parcJSONArray_Create();
+ PARCJSONValue *value = parcJSONValue_CreateFromCString("Some Pig");
+ parcJSONArray_AddValue(array, value);
+
+ parcJSON_AddArray(json, expectedName, array);
+ parcJSONArray_Release(&array);
+
+ const PARCJSONPair *pair = parcJSON_GetPairByName(json, expectedName);
+
+ PARCBuffer *actualName = parcJSONPair_GetName(pair);
+ PARCJSONValue *actualValue = parcJSONPair_GetValue(pair);
+ assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0,
+ "Expected name %s, actual %s", expectedName, (char *) parcBuffer_ToString(actualName));
+ assertTrue(parcJSONValue_IsArray(actualValue), "Expect value to be type PARCJSONArray");
+ array = parcJSONValue_GetArray(actualValue);
+ PARCJSONValue *result = parcJSONArray_GetValue(array, 0);
+ assertTrue(parcBuffer_Equals(parcJSONValue_GetString(result), parcJSONValue_GetString(value)),
+ "Expected %s actual %s",
+ parcJSONValue_ToString(value),
+ parcJSONValue_ToString(result));
+
+ parcJSONValue_Release(&value);
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSON, parcJSON_AddValue)
+{
+ PARCJSON *json = parcJSON_Create();
+
+ char *expectedName = "value";
+
+ PARCJSONValue *value = parcJSONValue_CreateFromCString("Some Pig");
+
+ parcJSON_AddValue(json, expectedName, value);
+
+ const PARCJSONPair *pair = parcJSON_GetPairByName(json, expectedName);
+
+ PARCBuffer *actualName = parcJSONPair_GetName(pair);
+ PARCJSONValue *actualValue = parcJSONPair_GetValue(pair);
+ assertTrue(strcmp(expectedName, parcBuffer_Overlay(actualName, 0)) == 0,
+ "Expected name %s, actual %s", expectedName, (char *) parcBuffer_ToString(actualName));
+ assertTrue(parcJSONValue_IsString(actualValue), "Expect value to be type PARCJSONArray");
+ assertTrue(parcBuffer_Equals(parcJSONValue_GetString(actualValue), parcJSONValue_GetString(value)),
+ "Expected %s actual %s",
+ parcJSONValue_ToString(value),
+ parcJSONValue_ToString(actualValue));
+
+ parcJSONValue_Release(&value);
+
+ parcJSON_Release(&json);
+}
+
+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(parc_JSON);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_JSONArray.c b/libparc/parc/algol/test/test_parc_JSONArray.c
new file mode 100755
index 00000000..d0ad9ec5
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_JSONArray.c
@@ -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.
+ */
+
+#include "../parc_JSONArray.c"
+
+#include <LongBow/unit-test.h>
+#include <stdio.h>
+
+#include "../parc_List.h"
+#include "../parc_ArrayList.h"
+#include "../parc_SafeMemory.h"
+#include "../parc_Memory.h"
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_JSONArray)
+{
+ // 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(Static);
+ LONGBOW_RUN_TEST_FIXTURE(parc_JSONArray);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_JSONArray)
+{
+ 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_JSONArray)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(parc_JSONArray)
+{
+ LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_CreateRelease);
+ LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_Equals);
+ LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_AddValue);
+ LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_GetLength);
+ LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_GetValue);
+ LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_BuildString);
+ LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_ToString);
+ LONGBOW_RUN_TEST_CASE(parc_JSONArray, parcJSONArray_Display);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(parc_JSONArray)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(parc_JSONArray)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_CreateRelease)
+{
+ PARCJSONArray *expected = parcJSONArray_Create();
+ parcJSONArray_AssertValid(expected);
+ assertNotNull(expected, "Expected non-null return value from parcJSONArray_Create");
+
+ PARCJSONArray *actual = parcJSONArray_Acquire(expected);
+ parcJSONArray_AssertValid(actual);
+
+ parcJSONArray_Release(&actual);
+ assertNull(actual, "Expected null value set by parcJSONArray_Release");
+ parcJSONArray_AssertValid(expected);
+
+ parcJSONArray_Release(&expected);
+ assertNull(expected, "Expected null value set by parcJSONArray_Release");
+}
+
+LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_Equals)
+{
+ PARCJSONArray *x = parcJSONArray_Create();
+ PARCJSONArray *y = parcJSONArray_Create();
+ PARCJSONArray *z = parcJSONArray_Create();
+
+ PARCJSONArray *notEqual1 = parcJSONArray_Create();
+ PARCJSONValue *value = parcJSONValue_CreateFromCString("Hello");
+ parcJSONArray_AddValue(notEqual1, value);
+ parcJSONValue_Release(&value);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONArray_Equals, x, y, z, notEqual1);
+
+ parcJSONArray_Release(&x);
+ parcJSONArray_Release(&y);
+ parcJSONArray_Release(&z);
+ parcJSONArray_Release(&notEqual1);
+}
+
+LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_AddValue)
+{
+ PARCJSONArray *expected = parcJSONArray_Create();
+ PARCJSONValue *value = parcJSONValue_CreateFromInteger(10);
+ parcJSONArray_AddValue(expected, value);
+ parcJSONValue_Release(&value);
+
+ parcJSONArray_Release(&expected);
+}
+
+LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_GetLength)
+{
+ PARCJSONArray *expected = parcJSONArray_Create();
+ PARCJSONValue *value = parcJSONValue_CreateFromInteger(10);
+ parcJSONArray_AddValue(expected, value);
+ parcJSONValue_Release(&value);
+ assertTrue(parcJSONArray_GetLength(expected) == 1, "Expected a length of 1");
+
+ parcJSONArray_Release(&expected);
+}
+
+LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_GetValue)
+{
+ PARCJSONArray *array = parcJSONArray_Create();
+ PARCJSONValue *expected = parcJSONValue_CreateFromInteger(10);
+ parcJSONArray_AddValue(array, expected);
+
+ PARCJSONValue *actual = parcJSONArray_GetValue(array, 0);
+
+ assertTrue(expected == actual, "Expected different value");
+
+ parcJSONValue_Release(&expected);
+ parcJSONArray_Release(&array);
+}
+
+LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_BuildString)
+{
+ PARCJSONArray *array = parcJSONArray_Create();
+ PARCJSONValue *expected = parcJSONValue_CreateFromInteger(10);
+ parcJSONArray_AddValue(array, expected);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcJSONArray_BuildString(array, composer, false);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ parcBufferComposer_Release(&composer);
+ char *result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ assertTrue(strlen(result) > 0, "Expected non-empty string result");
+
+ parcMemory_Deallocate((void **) &result);
+
+ composer = parcBufferComposer_Create();
+ parcJSONArray_BuildString(array, composer, true);
+ tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ parcBufferComposer_Release(&composer);
+ result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ assertTrue(strlen(result) > 0, "Expected non-empty string result");
+
+ parcMemory_Deallocate((void **) &result);
+
+ parcJSONValue_Release(&expected);
+ parcJSONArray_Release(&array);
+}
+
+LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_ToString)
+{
+ PARCJSONArray *array = parcJSONArray_Create();
+ PARCJSONValue *expected = parcJSONValue_CreateFromInteger(10);
+ parcJSONArray_AddValue(array, expected);
+ parcJSONValue_Release(&expected);
+
+ const char *string = parcJSONArray_ToString(array);
+
+ parcMemory_Deallocate((void **) &string);
+
+ parcJSONArray_Release(&array);
+}
+
+LONGBOW_TEST_CASE(parc_JSONArray, parcJSONArray_Display)
+{
+ PARCJSONArray *array = parcJSONArray_Create();
+ PARCJSONValue *expected = parcJSONValue_CreateFromInteger(10);
+ parcJSONArray_AddValue(array, expected);
+ parcJSONValue_Release(&expected);
+
+ parcJSONArray_Display(array, 0);
+
+ parcJSONArray_Release(&array);
+}
+
+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(parc_JSONArray);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_JSONPair.c b/libparc/parc/algol/test/test_parc_JSONPair.c
new file mode 100644
index 00000000..b8c0c3f9
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_JSONPair.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_JSONPair.c"
+#include <LongBow/unit-test.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include "../parc_List.h"
+#include "../parc_ArrayList.h"
+#include "../parc_SafeMemory.h"
+#include "../parc_Memory.h"
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_JSONPair)
+{
+ // 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(Static);
+ LONGBOW_RUN_TEST_FIXTURE(JSONPair);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_JSONPair)
+{
+ 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_JSONPair)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(JSONPair)
+{
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateAcquireRelease);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_BuildString);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_ToString);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_Display);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_Equals);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_Parser);
+
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateNULL);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateValue);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateString);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateFromBoolean);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateFromInteger);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateFromFloat);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateFromJSONArray);
+ LONGBOW_RUN_TEST_CASE(JSONPair, parcJSONPair_CreateFromJSON);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(JSONPair)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(JSONPair)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateAcquireRelease)
+{
+ PARCBuffer *name = parcBuffer_WrapCString("name");
+
+ PARCBuffer *stringValue = parcBuffer_WrapCString("foo");
+ PARCJSONValue *value = parcJSONValue_CreateFromString(stringValue);
+ parcBuffer_Release(&stringValue);
+
+ PARCJSONPair *pair = parcJSONPair_Create(name, value);
+
+ assertTrue(parcBuffer_Equals(name, pair->name),
+ "Expected '%s' actual '%s'", parcBuffer_ToString(name), parcBuffer_ToString(pair->name));
+ assertTrue(value == pair->value,
+ "Expected %p' actual %p", (void *) value, (void *) pair->value);
+
+ PARCJSONPair *reference = parcJSONPair_Acquire(pair);
+
+ assertTrue(reference == pair,
+ "Expected parcJSONPair_Acquire to return the same pointer as the original.");
+
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&value);
+ parcJSONPair_Release(&reference);
+ parcJSONPair_Release(&pair);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_Display)
+{
+ PARCBuffer *name = parcBuffer_WrapCString("name");
+ PARCBuffer *value = parcBuffer_WrapCString("foo");
+
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromString(value);
+ parcBuffer_Release(&value);
+ PARCJSONPair *pair = parcJSONPair_Create(name, jsonValue);
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&jsonValue);
+
+ parcJSONPair_Display(pair, 0);
+
+ parcJSONPair_Release(&pair);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_BuildString)
+{
+ PARCBuffer *name = parcBuffer_WrapCString("name");
+ PARCBuffer *value = parcBuffer_WrapCString("foo/bar");
+
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromString(value);
+ parcBuffer_Release(&value);
+ PARCJSONPair *pair = parcJSONPair_Create(name, jsonValue);
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&jsonValue);
+
+ // umcompressed
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcJSONPair_BuildString(pair, composer, false);
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ char *expected = "\"name\" : \"foo\\/bar\"";
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ // compressed
+ composer = parcBufferComposer_Create();
+ parcJSONPair_BuildString(pair, composer, true);
+ tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ expected = "\"name\":\"foo/bar\"";
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ parcJSONPair_Release(&pair);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_ToString)
+{
+ PARCBuffer *name = parcBuffer_WrapCString("name");
+ PARCBuffer *value = parcBuffer_WrapCString("foo");
+
+ PARCJSONValue *jsonValue = parcJSONValue_CreateFromString(value);
+ parcBuffer_Release(&value);
+ PARCJSONPair *pair = parcJSONPair_Create(name, jsonValue);
+ parcBuffer_Release(&name);
+ parcJSONValue_Release(&jsonValue);
+
+ char *expected = "\"name\" : \"foo\"";
+ char *actual = parcJSONPair_ToString(pair);
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ parcJSONPair_Release(&pair);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateNULL)
+{
+ char *name = "MyNull";
+ PARCBuffer *expectedName = parcBuffer_AllocateCString(name);
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromNULL(name);
+
+ assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)),
+ "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair)));
+
+ assertTrue(parcJSONValue_IsNull(parcJSONPair_GetValue(pair)),
+ "Expected a JSON Null value.");
+
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&expectedName);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateValue)
+{
+ char *name = "MyNull";
+ PARCBuffer *expectedName = parcBuffer_AllocateCString(name);
+ PARCJSONValue *value = parcJSONValue_CreateFromCString("Some Pig");
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromJSONValue(name, value);
+
+ assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)),
+ "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair)));
+
+ assertTrue(parcJSONValue_IsString(parcJSONPair_GetValue(pair)),
+ "Expected a String value.");
+
+ assertTrue(parcJSONPair_GetValue(pair) == value, "Expect values to be equal");
+
+ parcJSONValue_Release(&value);
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&expectedName);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateString)
+{
+ char *name = "MyNull";
+ char *value = "value";
+ PARCBuffer *expectedName = parcBuffer_AllocateCString(name);
+ PARCJSONValue *expectedValue = parcJSONValue_CreateFromCString(value);
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromString(name, value);
+
+ assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)),
+ "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair)));
+ assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)),
+ "Expected value '%s', Got '%s'", value, parcBuffer_ToString(parcJSONValue_GetString(parcJSONPair_GetValue(pair))));
+ assertTrue(parcJSONValue_IsString(parcJSONPair_GetValue(pair)),
+ "Expected a JSON String value.");
+
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&expectedName);
+ parcJSONValue_Release(&expectedValue);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateFromBoolean)
+{
+ char *name = "MyNull";
+ bool value = true;
+ PARCBuffer *expectedName = parcBuffer_AllocateCString(name);
+ PARCJSONValue *expectedValue = parcJSONValue_CreateFromBoolean(value);
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromBoolean(name, value);
+
+ assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)),
+ "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair)));
+ assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)),
+ "Expected value '%d', Got '%d'", value, parcJSONValue_GetBoolean(parcJSONPair_GetValue(pair)));
+
+ assertTrue(parcJSONValue_IsBoolean(parcJSONPair_GetValue(pair)),
+ "Expected a JSON Boolean value.");
+
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&expectedName);
+ parcJSONValue_Release(&expectedValue);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateFromInteger)
+{
+ char *name = "MyNull";
+ int value = 31415;
+ PARCBuffer *expectedName = parcBuffer_AllocateCString(name);
+ PARCJSONValue *expectedValue = parcJSONValue_CreateFromInteger(value);
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromInteger(name, value);
+
+ assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)),
+ "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair)));
+ assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)),
+ "Expected value '%d', Got '%" PRIi64 "'", value, parcJSONValue_GetInteger(parcJSONPair_GetValue(pair)));
+
+ assertTrue(parcJSONValue_IsNumber(parcJSONPair_GetValue(pair)),
+ "Expected a JSON Integer value.");
+
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&expectedName);
+ parcJSONValue_Release(&expectedValue);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateFromFloat)
+{
+ char *name = "MyNull";
+ double value = 3.1;
+ PARCBuffer *expectedName = parcBuffer_AllocateCString(name);
+ PARCJSONValue *expectedValue = parcJSONValue_CreateFromFloat(value);
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromDouble(name, value);
+
+ assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)),
+ "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair)));
+ assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)),
+ "Expected %g, got %Lg", value, parcJSONValue_GetFloat(parcJSONPair_GetValue(pair)));
+
+ assertTrue(parcJSONValue_IsNumber(parcJSONPair_GetValue(pair)),
+ "Expected a JSON number value.");
+
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&expectedName);
+ parcJSONValue_Release(&expectedValue);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateFromJSONArray)
+{
+ char *name = "MyNull";
+ PARCJSONArray *array = parcJSONArray_Create();
+
+ PARCBuffer *expectedName = parcBuffer_AllocateCString(name);
+ PARCJSONValue *expectedValue = parcJSONValue_CreateFromJSONArray(array);
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromJSONArray(name, array);
+ parcJSONArray_Release(&array);
+
+ assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)),
+ "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair)));
+ assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)),
+ "Expected the value to be equal the same array provided");
+
+ assertTrue(parcJSONValue_IsArray(parcJSONPair_GetValue(pair)),
+ "Expected a JSON Array value.");
+
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&expectedName);
+ parcJSONValue_Release(&expectedValue);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_CreateFromJSON)
+{
+ char *name = "MyNull";
+ PARCJSON *value = parcJSON_Create();
+
+ PARCBuffer *expectedName = parcBuffer_AllocateCString(name);
+ PARCJSONValue *expectedValue = parcJSONValue_CreateFromJSON(value);
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromJSON(name, value);
+
+ assertTrue(parcBuffer_Equals(expectedName, parcJSONPair_GetName(pair)),
+ "Expected name '%s', got '%s'", name, parcBuffer_ToString(parcJSONPair_GetName(pair)));
+ assertTrue(parcJSONValue_Equals(expectedValue, parcJSONPair_GetValue(pair)),
+ "Expected %s", parcJSON_ToString(value));
+
+ assertTrue(parcJSONValue_IsJSON(parcJSONPair_GetValue(pair)),
+ "Expected a JSON Object value.");
+
+ parcJSONPair_Release(&pair);
+ parcBuffer_Release(&expectedName);
+ parcJSONValue_Release(&expectedValue);
+ parcJSON_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_Equals)
+{
+ char *name = "MyNull";
+ char *unequalName = "foo";
+ int value = 31415;
+ int unequalValue = 141;
+
+ PARCJSONPair *pair = parcJSONPair_CreateFromInteger(name, value);
+ PARCJSONPair *y = parcJSONPair_CreateFromInteger(name, value);
+ PARCJSONPair *z = parcJSONPair_CreateFromInteger(name, value);
+ PARCJSONPair *unequal1 = parcJSONPair_CreateFromInteger(name, unequalValue);
+ PARCJSONPair *unequal2 = parcJSONPair_CreateFromInteger(unequalName, unequalValue);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONPair_Equals, pair, y, z, unequal1, unequal2);
+
+ parcJSONPair_Release(&pair);
+ parcJSONPair_Release(&y);
+ parcJSONPair_Release(&z);
+ parcJSONPair_Release(&unequal1);
+ parcJSONPair_Release(&unequal2);
+}
+
+LONGBOW_TEST_CASE(JSONPair, parcJSONPair_Parser)
+{
+ PARCBuffer *buffer = parcBuffer_AllocateCString("\"name\" : \"value\"");
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONPair *pair = parcJSONPair_Parser(parser);
+
+ assertTrue(parcBuffer_Position(parcJSONPair_GetName(pair)) == 0, "Expected the JSONPair name buffer to be 'reset'");
+
+ parcJSONPair_Release(&pair);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+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(parc_JSONPair);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_JSONParser.c b/libparc/parc/algol/test/test_parc_JSONParser.c
new file mode 100755
index 00000000..63bcea8d
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_JSONParser.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/unit-test.h>
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <math.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+#include "../parc_JSONParser.c"
+
+#include <parc/algol/parc_JSONValue.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_StdlibMemory.h>
+#include <parc/algol/parc_Memory.h>
+
+LONGBOW_TEST_RUNNER(parc_JSONParser)
+{
+ // 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(Static);
+ LONGBOW_RUN_TEST_FIXTURE(JSONParse_CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(JSONParse);
+// LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_JSONParser)
+{
+ 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_JSONParser)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+LONGBOW_TEST_FIXTURE(JSONParse_CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(JSONParse_CreateAcquireRelease, parcJSONParser_Create);
+ LONGBOW_RUN_TEST_CASE(JSONParse_CreateAcquireRelease, parcJSONParser_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(JSONParse_CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(JSONParse_CreateAcquireRelease)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(JSONParse_CreateAcquireRelease, parcJSONParser_Create)
+{
+ char *string = "\"string\"";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+ assertNull(parser,
+ "Expected parcJSONParser_Release to set the reference pointer to NULL");
+}
+
+LONGBOW_TEST_CASE(JSONParse_CreateAcquireRelease, parcJSONParser_AcquireRelease)
+{
+ char *string = "\"string\"";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *expected = parcJSONParser_Create(buffer);
+
+ PARCJSONParser *actual = parcJSONParser_Acquire(expected);
+ assertTrue(actual == expected,
+ "Expected the acquired reference to be the same as the original instance.");
+
+ parcJSONParser_Release(&actual);
+ assertNull(actual,
+ "Expected parcJSONParser_Release to set the reference pointer to NULL");
+
+ parcJSONParser_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_FIXTURE(JSONParse)
+{
+ LONGBOW_RUN_TEST_CASE(JSONParse, parcJSONString_Parser);
+ LONGBOW_RUN_TEST_CASE(JSONParse, parcJSONParser_RequireString_Fail);
+ LONGBOW_RUN_TEST_CASE(JSONParse, parcJSONString_Parser_Quoted);
+ LONGBOW_RUN_TEST_CASE(JSONParse, parcJSON_Parse);
+
+ LONGBOW_RUN_TEST_CASE(JSONParse, parcJSON_ParseFile);
+ LONGBOW_RUN_TEST_CASE(JSONParse, parcJSON_ParseFileToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(JSONParse)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(JSONParse)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(JSONParse, parcJSONString_Parser)
+{
+ char *string = "\"\\\" \\\\ \\b \\f \\n \\r \\t \\/\"";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+
+ PARCBuffer *expected = parcBuffer_AllocateCString("\" \\ \b \f \n \r \t /");
+ PARCBuffer *actual = parcJSONParser_ParseString(parser);
+
+ assertTrue(parcBuffer_Equals(expected, actual), "Expected string");
+
+ parcBuffer_Release(&actual);
+ parcBuffer_Release(&expected);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONParse, parcJSONParser_RequireString_Fail)
+{
+ char *string = "\"string\"";
+ char *requiredString = "foo";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+
+ bool actual = parcJSONParser_RequireString(parser, requiredString);
+
+ assertFalse(actual, "Expected parcJSONParser_RequireString to fail");
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONParse, parcJSONString_Parser_Quoted)
+{
+ char *string = "\"str\\\"ing\"";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+
+ PARCBuffer *expected = parcBuffer_WrapCString("str\"ing");
+ PARCBuffer *actual = parcJSONParser_ParseString(parser);
+
+ assertTrue(parcBuffer_Equals(expected, actual), "Expected string");
+
+ parcBuffer_Release(&actual);
+ parcBuffer_Release(&expected);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONParse, parcJSON_Parse)
+{
+ char *expected = "{ \"string\" : \"string\", \"null\" : null, \"true\" : true, \"false\" : false, \"integer\" : 31415, \"float\" : 3.141500, \"array\" : [ null, false, true, 31415, \"string\", [ null, false, true, 31415, \"string\" ], { } ] }";
+
+ expected = "{ \"integer\" : 31415 }";
+
+ expected = "{ \"string\" : \"string\", \"null\" : null, \"true\" : true, \"false\" : false, \"integer\" : 31415, \"array\" : [ null, false, true, 31415, \"string\", [ null, false, true, 31415, \"string\" ], { \"string\" : \"string\" } ] }";
+
+ PARCJSON *json = parcJSON_ParseString(expected);
+ assertNotNull(json, "Parse error for %s", expected);
+
+ char *actual = parcJSON_ToString(json);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+
+ printf("%s\n", actual);
+ parcMemory_Deallocate((void **) &actual);
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSONParse, parcJSON_ParseFile)
+{
+ char *string = NULL;
+ size_t nread = longBowDebug_ReadFile("data.json", &string);
+ assertTrue(nread != -1, "Cannot read '%s'", "data.json");
+
+ PARCJSON *json = parcJSON_ParseString(string);
+
+ assertNotNull(json, "parcJSON_ParseString failed");
+
+ // assertTrue(longBowDebug_WriteFile("/tmp/test_parc_JSON.json", actual, strlen(actual)) != 0,
+ // "Can't write file");
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSONParse, parcJSON_ParseFileToString)
+{
+ char *string = NULL;
+ size_t nread = longBowDebug_ReadFile("data.json", &string);
+ assertTrue(nread != -1, "Cannot read '%s'", "data.json");
+
+ PARCJSON *json = parcJSON_ParseString(string);
+
+ assertNotNull(json, "parcJSON_ParseString failed");
+
+ char *actual = parcJSON_ToString(json);
+
+ // assertTrue(longBowDebug_WriteFile("/tmp/test_parc_JSON.json", actual, strlen(actual)) != 0,
+ // "Can't write file");
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Performance)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcJSON_ParseFileToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ parcMemory_SetInterface(&PARCStdlibMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, parcJSON_ParseFileToString)
+{
+ char *string = NULL;
+ size_t nread = longBowDebug_ReadFile("citylots.json", &string);
+ assertTrue(nread != -1, "Cannot read '%s'", "citylots.json");
+
+ PARCJSON *json = parcJSON_ParseString(string);
+
+ assertNotNull(json, "parcJSON_ParseString failed");
+
+ char *actual = parcJSON_ToString(json);
+
+ // assertTrue(longBowDebug_WriteFile("/tmp/test_parc_JSON.json", actual, strlen(actual)) != 0,
+ // "Can't write file");
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcJSON_Release(&json);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_JSONParser);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_JSONValue.c b/libparc/parc/algol/test/test_parc_JSONValue.c
new file mode 100644
index 00000000..804eb690
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_JSONValue.c
@@ -0,0 +1,1365 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_JSONValue.c"
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include "../parc_List.h"
+#include "../parc_ArrayList.h"
+#include "../parc_SafeMemory.h"
+#include "../parc_Memory.h"
+
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_JSONValue)
+{
+ // 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(Static);
+ LONGBOW_RUN_TEST_FIXTURE(JSONValue_CreateAcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(JSONValue);
+ LONGBOW_RUN_TEST_FIXTURE(JSONValueParsing);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_JSONValue)
+{
+ 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_JSONValue)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(JSONValue_CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(JSONValue_CreateAcquireRelease, _createValue);
+ LONGBOW_RUN_TEST_CASE(JSONValue_CreateAcquireRelease, parcJSONValue_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(JSONValue_CreateAcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(JSONValue_CreateAcquireRelease)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(JSONValue_CreateAcquireRelease, _createValue)
+{
+ PARCJSONValue *result = parcJSONValue_CreateFromNULL();
+
+ assertNotNull(result, "Expected non-null return value from _createValue");
+ assertTrue(parcJSONValue_IsNull(result),
+ "Expected PARCJSONValueType_Null");
+
+ parcJSONValue_Release(&result);
+ assertNull(result, "Expected parcJSONValue_Release to NULL the instance pointer.");
+}
+
+
+LONGBOW_TEST_CASE(JSONValue_CreateAcquireRelease, parcJSONValue_AcquireRelease)
+{
+ PARCJSONValue *result = parcJSONValue_CreateFromNULL();
+
+ assertNotNull(result, "Expected non-null return value from _createValue");
+ assertTrue(parcJSONValue_IsNull(result),
+ "Expected PARCJSONValueType_Null");
+
+ PARCJSONValue *actual = parcJSONValue_Acquire(result);
+ assertTrue(result == actual, "Expected parcJSONValue_Acquire return value to be same as the original.");
+
+ parcJSONValue_Release(&actual);
+ parcJSONValue_Release(&result);
+ assertNull(result, "Expected parcJSONValue_Release to NULL the instance pointer.");
+}
+
+
+LONGBOW_TEST_FIXTURE(JSONValue)
+{
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_NULL);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Boolean);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Float);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Integer);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_String);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_JSON);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Array);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Timespec);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Create_Timeval);
+
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_IsValid);
+
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Display);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_BuildString);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_NULL);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_Array);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_Boolean);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_Float);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_Integer);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_String);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_CreateCString);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_ToString_JSON);
+
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_NULL);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_Boolean);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_Integer);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_Float);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_String);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_Object);
+ LONGBOW_RUN_TEST_CASE(JSONValue, parcJSONValue_Equals_Array);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(JSONValue)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(JSONValue)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_IsValid)
+{
+ bool actual = parcJSONValue_IsValid(NULL);
+ assertFalse(actual, "Expected a NULL value to be invalid");
+
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+
+ actual = parcJSONValue_IsValid(value);
+ parcJSONValue_Release(&value);
+ assertTrue(actual, "Expected a NULL value to be invalid");
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_JSON)
+{
+ PARCJSON *json = parcJSON_Create();
+ PARCJSONValue *value = parcJSONValue_CreateFromJSON(json);
+
+ assertTrue(parcJSONValue_IsJSON(value),
+ "Expected PARCJSONValueType_JSON");
+
+ assertTrue(parcJSONValue_GetJSON(value) == json,
+ "Expected parcJSONValue_GetJSON to return the original instance pointer.");
+ parcJSONValue_Release(&value);
+ assertNull(value, "Expected NULL pointer.");
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Timeval)
+{
+ struct timeval timeval = { .tv_sec = 42, .tv_usec = 23 };
+ PARCJSONValue *value = parcJSONValue_CreateFromTimeval(&timeval);
+
+ assertTrue(parcJSONValue_IsJSON(value),
+ "Expected PARCJSONValueType_JSON");
+
+ struct timeval actual;
+ parcJSONValue_GetTimeval(value, &actual);
+ assertTrue(timeval.tv_sec == actual.tv_sec, "Expected seconds to be equal.");
+ assertTrue(timeval.tv_usec == actual.tv_usec, "Expected seconds to be equal.");
+
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Timespec)
+{
+ struct timespec timespec = { .tv_sec = 42, .tv_nsec = 23 };
+ PARCJSONValue *value = parcJSONValue_CreateFromTimespec(&timespec);
+
+ assertTrue(parcJSONValue_IsJSON(value),
+ "Expected PARCJSONValueType_JSON");
+
+ struct timespec testTS;
+ parcJSONValue_GetTimespec(value, &testTS);
+ assertTrue(memcmp(&timespec, &testTS, sizeof(struct timespec)) == 0,
+ "Expected parcJSONValue_GetTimespec to return the original instance pointer.");
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_NULL)
+{
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+
+ assertTrue(value->type == PARCJSONValueType_Null,
+ "Expected PARCJSONValueType_Null, actual %d", value->type);
+ assertTrue(parcJSONValue_IsNull(value),
+ "Expected PARCJSONValueType_Null");
+ parcJSONValue_Release(&value);
+ assertNull(value, "Expected NULL pointer.");
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Boolean)
+{
+ bool expected = true;
+ PARCJSONValue *value = parcJSONValue_CreateFromBoolean(expected);
+
+ assertTrue(value->type == PARCJSONValueType_Boolean,
+ "Expected PARCJSONValueType_BooleanON_VALUE_BOOLEAN, actual %d", value->type);
+ assertTrue(value->value.boolean == expected, "Expected %d actual %d", expected, value->value.boolean);
+
+ assertTrue(parcJSONValue_IsBoolean(value),
+ "Expected PARCJSONValueType_Boolean");
+ assertTrue(parcJSONValue_GetBoolean(value), "Expected value to be true");
+ parcJSONValue_Release(&value);
+ assertNull(value, "Expected NULL pointer.");
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Float)
+{
+ double expected = 3.1415;
+ PARCJSONValue *value = parcJSONValue_CreateFromFloat(expected);
+
+ assertTrue(parcJSONValue_IsNumber(value),
+ "Expected parcJSONValue_IsNumber to be true.");
+ assertTrue(parcJSONValue_GetFloat(value) == expected,
+ "Expected %g, actual %Lg", expected, parcJSONValue_GetFloat(value));
+
+ char *expectedString = "3.141500";
+ char *actualString = parcJSONValue_ToString(value);
+ assertTrue(strcmp(expectedString, actualString) == 0, "Exepcted %s, actual %s", expectedString, actualString);
+ parcMemory_Deallocate((void **) &actualString);
+
+ parcJSONValue_Release(&value);
+ assertNull(value, "Expected NULL pointer.");
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Integer)
+{
+ int expected = 31415;
+ PARCJSONValue *value = parcJSONValue_CreateFromInteger(expected);
+
+ assertTrue(parcJSONValue_IsNumber(value),
+ "Expected parcJSONValue_IsNumber");
+ int64_t actual = parcJSONValue_GetInteger(value);
+ assertTrue(expected == actual, "Expected %d, actual %" PRIi64 "", expected, actual);
+ parcJSONValue_Release(&value);
+ assertNull(value, "Expected NULL pointer.");
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_String)
+{
+ PARCBuffer *expected = parcBuffer_WrapCString("31415");
+ PARCJSONValue *value = parcJSONValue_CreateFromString(expected);
+
+ assertTrue(value->type == PARCJSONValueType_String,
+ "Expected parcJSONValueType.String, actual %d", value->type);
+ assertTrue(parcBuffer_Equals(value->value.string, expected),
+ "Expected %s actual %s", parcBuffer_ToString(expected), parcBuffer_ToString(value->value.string));
+ assertTrue(parcJSONValue_IsString(value),
+ "Expected PARCJSONValueType_String");
+
+ assertTrue(parcBuffer_Equals(parcJSONValue_GetString(value), expected), "Expected value did not match actual value");
+ parcJSONValue_Release(&value);
+ assertNull(value, "Expected NULL pointer.");
+ parcBuffer_Release(&expected);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_CreateCString)
+{
+ PARCBuffer *expected = parcBuffer_WrapCString("31415");
+
+ PARCJSONValue *value = parcJSONValue_CreateFromCString("31415");
+
+ assertTrue(value->type == PARCJSONValueType_String,
+ "Expected parcJSONValueType.String, actual %d", value->type);
+
+ assertTrue(parcBuffer_Equals(parcJSONValue_GetString(value), expected), "Assert:")
+ {
+ char *expectedString = parcBuffer_ToString(expected);
+ char *actualString = parcBuffer_ToString(parcJSONValue_GetString(value));
+ printf("Expected '%s', actual '%s'", expectedString, actualString);
+ parcMemory_Deallocate((void **) &expectedString);
+ parcMemory_Deallocate((void **) &actualString);
+ }
+
+ parcJSONValue_Release(&value);
+ assertNull(value, "Expected NULL pointer.");
+ parcBuffer_Release(&expected);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Create_Array)
+{
+ PARCJSONArray *array = parcJSONArray_Create();
+
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromJSONArray(array);
+
+ parcJSONValue_Release(&value);
+
+ parcJSONArray_Release(&array);
+ assertNull(value, "Expected NULL pointer.");
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_BuildString)
+{
+ PARCJSONArray *array = parcJSONArray_Create();
+
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromBoolean(false);
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromBoolean(true);
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromInteger(31415);
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ PARCBuffer *stringValue = parcBuffer_WrapCString("stringA/stringB");
+ value = parcJSONValue_CreateFromString(stringValue);
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+ parcBuffer_Release(&stringValue);
+
+ value = parcJSONValue_CreateFromJSONArray(array);
+ parcJSONArray_Release(&array);
+
+ // Uncompacted
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcJSONValue_BuildString(value, composer, false);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ char *expected = "[ null, false, true, 31415, \"stringA\\/stringB\" ]";
+
+ assertTrue(strcmp(actual, expected) == 0,
+ "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ // Compacted
+ composer = parcBufferComposer_Create();
+ parcJSONValue_BuildString(value, composer, true);
+
+ tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+
+ expected = "[null,false,true,31415,\"stringA/stringB\"]";
+
+ assertTrue(strcmp(actual, expected) == 0,
+ "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_Array)
+{
+ PARCJSONArray *array = parcJSONArray_Create();
+
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromBoolean(false);
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromBoolean(true);
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromInteger(31415);
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+
+ PARCBuffer *stringValue = parcBuffer_WrapCString("stringA/stringB");
+ value = parcJSONValue_CreateFromString(stringValue);
+ parcJSONArray_AddValue(array, value);
+ parcJSONValue_Release(&value);
+ parcBuffer_Release(&stringValue);
+
+ value = parcJSONValue_CreateFromJSONArray(array);
+ parcJSONArray_Release(&array);
+
+ char *expected = "[ null, false, true, 31415, \"stringA\\/stringB\" ]";
+ char *actual = parcJSONValue_ToString(value);
+
+ assertTrue(strcmp(actual, expected) == 0,
+ "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Display)
+{
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+ parcJSONValue_Display(value, 0);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromBoolean(true);
+ parcJSONValue_Display(value, 0);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromCString("hello");
+ parcJSONValue_Display(value, 0);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromFloat(3.14);
+ parcJSONValue_Display(value, 0);
+ parcJSONValue_Release(&value);
+
+ value = parcJSONValue_CreateFromInteger(314);
+ parcJSONValue_Display(value, 0);
+ parcJSONValue_Release(&value);
+
+ PARCJSONArray *array = parcJSONArray_Create();
+ value = parcJSONValue_CreateFromJSONArray(array);
+ parcJSONValue_Display(value, 0);
+ parcJSONValue_Release(&value);
+ parcJSONArray_Release(&array);
+
+ PARCJSON *json = parcJSON_Create();
+ value = parcJSONValue_CreateFromJSON(json);
+ parcJSONValue_Display(value, 0);
+ parcJSONValue_Release(&value);
+ parcJSON_Release(&json);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_NULL)
+{
+ char *expected = "null";
+ PARCJSONValue *value = parcJSONValue_CreateFromNULL();
+
+ char *actual = parcJSONValue_ToString(value);
+ assertTrue(strcmp(actual, expected) == 0, "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_Boolean)
+{
+ char *expected = "true";
+ PARCJSONValue *value = parcJSONValue_CreateFromBoolean(expected);
+
+ char *actual = parcJSONValue_ToString(value);
+ assertTrue(strcmp(actual, expected) == 0, "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_Float)
+{
+ struct test_values {
+ char *string;
+ long double value;
+ long double error;
+ } successful[] = {
+ { "-0.0415e-12", -0.0415e-12, 0.00001e-12 },
+ { "-0.0415e12", -0.0415e12, 0.00001e12 },
+ { "-0.0415", -0.0415, 0.00001 },
+ { "-3.0415", -3.0415, 0.00001 },
+ { "123.456", 123.456, 0.0001 },
+ { "123.456e78", 123.456e78, 0.0001e78 },
+ { "123.456e-78", 123.456e-78, 0.0001e-78 },
+ { "123.456e-78", 123.456e-78, 0.0001e-78 },
+ { "4e1", 40.0, 0.0001e-78 },
+ { NULL },
+ };
+
+ for (int i = 0; successful[i].string != NULL; i++) {
+ PARCBuffer *buffer = parcBuffer_WrapCString(successful[i].string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCJSONValue *expected = _parcJSONValue_NumberParser(parser);
+
+ char *string = parcJSONValue_ToString(expected);
+ assertTrue(strcmp(successful[i].string, string) == 0,
+ "Expected %s, actual %s", successful[i].string, string);
+ parcMemory_Deallocate((void **) &string);
+
+ parcJSONValue_Release(&expected);
+ parcJSONParser_Release(&parser);
+ }
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_Integer)
+{
+ char *expected = "31415";
+ PARCJSONValue *value = parcJSONValue_CreateFromInteger(31415);
+
+ char *actual = parcJSONValue_ToString(value);
+ assertTrue(strcmp(actual, expected) == 0,
+ "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_String)
+{
+ char *input = "31415\b";
+ char *expected = "\"31415\\b\"";
+
+ PARCBuffer *stringValue = parcBuffer_WrapCString(input);
+ PARCJSONValue *value = parcJSONValue_CreateFromString(stringValue);
+ parcBuffer_Release(&stringValue);
+
+ char *actual = parcJSONValue_ToString(value);
+ assertTrue(strcmp(actual, expected) == 0, "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_ToString_JSON)
+{
+ char *expected = "{ }";
+ PARCJSON *json = parcJSON_Create();
+ PARCJSONValue *value = parcJSONValue_CreateFromJSON(json);
+ parcJSON_Release(&json);
+
+ char *actual = parcJSONValue_ToString(value);
+ assertTrue(strcmp(actual, expected) == 0, "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcJSONValue_Release(&value);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_NULL)
+{
+ PARCJSONValue *example = parcJSONValue_CreateFromNULL();
+
+ PARCJSONValue *equal1 = parcJSONValue_CreateFromNULL();
+ PARCJSONValue *equal2 = parcJSONValue_CreateFromNULL();
+
+ PARCBuffer *stringBuffer = parcBuffer_AllocateCString("Hello");
+ PARCJSONValue *string = parcJSONValue_CreateFromString(stringBuffer);
+ parcBuffer_Release(&stringBuffer);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, example, equal1, equal2, string);
+
+ parcJSONValue_Release(&string);
+ parcJSONValue_Release(&equal2);
+ parcJSONValue_Release(&equal1);
+ parcJSONValue_Release(&example);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_Boolean)
+{
+ PARCJSONValue *example = parcJSONValue_CreateFromBoolean(true);
+
+ PARCJSONValue *equal1 = parcJSONValue_CreateFromBoolean(true);
+ PARCJSONValue *equal2 = parcJSONValue_CreateFromBoolean(true);
+
+ PARCJSONValue *unequal1 = parcJSONValue_CreateFromBoolean(false);
+
+ PARCBuffer *stringBuffer = parcBuffer_AllocateCString("Hello");
+ PARCJSONValue *string = parcJSONValue_CreateFromString(stringBuffer);
+ parcBuffer_Release(&stringBuffer);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, example, equal1, equal2, unequal1, string);
+
+ parcJSONValue_Release(&string);
+ parcJSONValue_Release(&unequal1);
+ parcJSONValue_Release(&equal2);
+ parcJSONValue_Release(&equal1);
+ parcJSONValue_Release(&example);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_Integer)
+{
+ PARCJSONValue *example = parcJSONValue_CreateFromInteger(31415);
+
+ PARCJSONValue *equal1 = parcJSONValue_CreateFromInteger(31415);
+ PARCJSONValue *equal2 = parcJSONValue_CreateFromInteger(31415);
+
+ PARCJSONValue *unequal1 = parcJSONValue_CreateFromInteger(4);
+
+ PARCBuffer *stringBuffer = parcBuffer_AllocateCString("Hello");
+ PARCJSONValue *string = parcJSONValue_CreateFromString(stringBuffer);
+ parcBuffer_Release(&stringBuffer);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, example, equal1, equal2, unequal1, string);
+
+ parcJSONValue_Release(&string);
+ parcJSONValue_Release(&unequal1);
+ parcJSONValue_Release(&equal2);
+ parcJSONValue_Release(&equal1);
+ parcJSONValue_Release(&example);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_Float)
+{
+ PARCJSONValue *example = parcJSONValue_CreateFromFloat(3.1415);
+
+ PARCJSONValue *equal1 = parcJSONValue_CreateFromFloat(3.1415);
+ PARCJSONValue *equal2 = parcJSONValue_CreateFromFloat(3.1415);
+
+ PARCJSONValue *unequal1 = parcJSONValue_CreateFromFloat(4.0);
+
+ PARCBuffer *stringBuffer = parcBuffer_AllocateCString("Hello");
+ PARCJSONValue *string = parcJSONValue_CreateFromString(stringBuffer);
+ parcBuffer_Release(&stringBuffer);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, example, equal1, equal2, unequal1, string);
+
+ parcJSONValue_Release(&string);
+ parcJSONValue_Release(&unequal1);
+ parcJSONValue_Release(&equal2);
+ parcJSONValue_Release(&equal1);
+ parcJSONValue_Release(&example);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_String)
+{
+ PARCBuffer *stringBuffer = parcBuffer_AllocateCString("Hello");
+ PARCJSONValue *example = parcJSONValue_CreateFromString(stringBuffer);
+ parcBuffer_Release(&stringBuffer);
+
+ stringBuffer = parcBuffer_AllocateCString("Hello");
+ PARCJSONValue *equal1 = parcJSONValue_CreateFromString(stringBuffer);
+ parcBuffer_Release(&stringBuffer);
+
+ stringBuffer = parcBuffer_AllocateCString("Hello");
+ PARCJSONValue *equal2 = parcJSONValue_CreateFromString(stringBuffer);
+ parcBuffer_Release(&stringBuffer);
+
+ PARCJSONValue *unequal1 = parcJSONValue_CreateFromFloat(4.0);
+
+ stringBuffer = parcBuffer_AllocateCString("World");
+ PARCJSONValue *string = parcJSONValue_CreateFromString(stringBuffer);
+ parcBuffer_Release(&stringBuffer);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, example, equal1, equal2, unequal1, string);
+
+ parcJSONValue_Release(&string);
+ parcJSONValue_Release(&unequal1);
+ parcJSONValue_Release(&equal2);
+ parcJSONValue_Release(&equal1);
+ parcJSONValue_Release(&example);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_Object)
+{
+ char *string = "{ \"name\" : 1, \"name2\" : 2 }";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCJSONValue *x = parcJSONValue_ObjectParser(parser);
+ parcJSONParser_Release(&parser);
+
+ assertTrue(parcJSONValue_IsJSON(x), "Expected a JSON Object value.");
+
+ buffer = parcBuffer_WrapCString(string);
+ parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCJSONValue *y = parcJSONValue_ObjectParser(parser);
+ parcJSONParser_Release(&parser);
+
+ buffer = parcBuffer_WrapCString(string);
+ parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCJSONValue *z = parcJSONValue_ObjectParser(parser);
+ parcJSONParser_Release(&parser);
+
+ PARCJSONValue *unequal1 = parcJSONValue_CreateFromFloat(4.0);
+
+ PARCJSON *json = parcJSON_Create();
+ PARCJSONValue *unequal2 = parcJSONValue_CreateFromJSON(json);
+ parcJSON_Release(&json);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, x, y, z, unequal1, unequal2);
+
+ parcJSONValue_Release(&x);
+ parcJSONValue_Release(&y);
+ parcJSONValue_Release(&z);
+ parcJSONValue_Release(&unequal1);
+ parcJSONValue_Release(&unequal2);
+}
+
+LONGBOW_TEST_CASE(JSONValue, parcJSONValue_Equals_Array)
+{
+ char *string = "[ \"name\", 1, true, false, null, [ ], { } ]";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCJSONValue *x = _parcJSONValue_ArrayParser(parser);
+ parcJSONParser_Release(&parser);
+
+ assertTrue(parcJSONValue_IsArray(x), "Expected a JSON Array value.");
+
+ buffer = parcBuffer_WrapCString(string);
+ parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCJSONValue *y = _parcJSONValue_ArrayParser(parser);
+ parcJSONParser_Release(&parser);
+
+ buffer = parcBuffer_WrapCString(string);
+ parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCJSONValue *z = _parcJSONValue_ArrayParser(parser);
+ parcJSONParser_Release(&parser);
+
+ PARCJSONValue *unequal1 = parcJSONValue_CreateFromFloat(4.0);
+
+ PARCJSONArray *array = parcJSONArray_Create();
+ PARCJSONValue *unequal2 = parcJSONValue_CreateFromJSONArray(array);
+ parcJSONArray_Release(&array);
+
+ parcObjectTesting_AssertEqualsFunction(parcJSONValue_Equals, x, y, z, unequal1, unequal2);
+
+ parcJSONValue_Release(&x);
+ parcJSONValue_Release(&y);
+ parcJSONValue_Release(&z);
+ parcJSONValue_Release(&unequal1);
+ parcJSONValue_Release(&unequal2);
+}
+
+LONGBOW_TEST_FIXTURE(JSONValueParsing)
+{
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_NullParser);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_NullParser_Bad);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_TrueParser);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_TrueParser_Bad);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_FalseParser);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_FalseParser_Bad);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_StringParser);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser_Bad_Pair);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser_Bad_Pair2);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_ArrayParser);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, _parcJSONValue_StringParser_BAD);
+
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_NumberParser_BatchedFloat);
+
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Comma);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_CloseBracket);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Null);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_True);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_False);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_String);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Array);
+ LONGBOW_RUN_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Object);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(JSONValueParsing)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(JSONValueParsing)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_NullParser)
+{
+ char *string = "null";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_NullParser(parser);
+
+ assertTrue(parcJSONValue_IsNull(actual), "Expected a JSON Null value.");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_NullParser_Bad)
+{
+ char *string = "nulx";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_NullParser(parser);
+
+ assertNull(actual, "Expected a NULL return value");
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_TrueParser)
+{
+ char *string = "true";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_TrueParser(parser);
+
+ assertTrue(parcJSONValue_IsBoolean(actual), "Expected a JSON Boolean value.");
+ assertTrue(parcJSONValue_GetBoolean(actual), "Expected true.");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_TrueParser_Bad)
+{
+ char *string = "trux";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_TrueParser(parser);
+
+ assertNull(actual, "Expected a NULL return value");
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_FalseParser)
+{
+ char *string = "false";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_FalseParser(parser);
+
+ assertTrue(parcJSONValue_IsBoolean(actual), "Expected a JSON Boolean value.");
+ assertFalse(parcJSONValue_GetBoolean(actual), "Expected false.");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_FalseParser_Bad)
+{
+ char *string = "falsx";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_FalseParser(parser);
+
+ assertNull(actual, "Expected a NULL return value");
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_StringParser)
+{
+ char *parserInput = "\"\\\" \\\\ \\b \\f \\n \\r \\t \\/\"";
+ PARCBuffer *buffer = parcBuffer_WrapCString(parserInput);
+ PARCBuffer *expected = parcBuffer_AllocateCString("\" \\ \b \f \n \r \t /");
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_StringParser(parser);
+
+ assertTrue(parcJSONValue_IsString(actual),
+ "Expected a JSON String value.");
+
+ assertTrue(parcBuffer_Equals(expected, actual->value.string),
+ "Expected '%s' actual '%s'", parcBuffer_ToString(expected), parcBuffer_ToString(actual->value.string))
+ {
+ parcBuffer_Display(expected, 0);
+ parcBuffer_Display(actual->value.string, 0);
+ }
+
+ char *string = parcJSONValue_ToString(actual);
+ assertTrue(strcmp(parserInput, string) == 0,
+ "Expected %s, actual %s", parserInput, string);
+
+ parcMemory_Deallocate((void **) &string);
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, _parcJSONValue_StringParser_BAD)
+{
+ char *bad[] = {
+ "\"\t\"",
+ "\"",
+ NULL
+ };
+
+ for (int i = 0; bad[i] != NULL; i++) {
+ char *parserInput = bad[i];
+ PARCBuffer *buffer = parcBuffer_WrapCString(parserInput);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_StringParser(parser);
+
+ assertNull(actual, "Expected failure");
+ parcBuffer_Release(&buffer);
+ parcJSONParser_Release(&parser);
+ }
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser)
+{
+ char *string = "{ \"name\" : 1, \"name2\" : 2 }";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_ObjectParser(parser);
+
+ assertTrue(parcJSONValue_IsJSON(actual), "Expected a JSON Object value.");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser_Bad_Pair)
+{
+ char *string = "{ \"name\" , \"name2\" : 2 }";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_ObjectParser(parser);
+
+ assertNull(actual, "Expected parcJSONValue_ObjectParser to return NULL indicating failure");
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_ObjectParser_Bad_Pair2)
+{
+ char *string = "{ 2 }";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_ObjectParser(parser);
+
+ assertNull(actual, "Expected parcJSONValue_ObjectParser to return NULL indicating failure");
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_ArrayParser)
+{
+ char *string = "[ \"name\", 1, true, false, null, [ ], { } ]";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = _parcJSONValue_ArrayParser(parser);
+
+ assertTrue(parcJSONValue_IsArray(actual), "Expected a JSON Array value.");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_NumberParser_BatchedFloat)
+{
+ struct test_values {
+ char *string;
+ char *expectedString;
+ long double floatValue;
+ int64_t integerValue;
+ long double floatTolerance;
+ } successful[] = {
+ { "0", "0", 0.0, 0, 0 },
+ { " 1", "1", 1.0, 1, 0 },
+ { "-1", "-1", -1.0, -1, 0 },
+ { "1e1", "1e1", 1.0e1, 10, 0 },
+ { "-2e1", "-2e1", -2.0e1, -2e1, 0 },
+ { "-2e+1", "-2e1", -2.0e+1, -2e+1, 0 },
+ { " 1.0", "1", 1.0, 1, 0 },
+ { "3e-1", "3e-1", 3e-1, 0, 0.01e-1 },
+ { "100e-2", "100e-2", 100e-2, 100e-2, 0.0001 },
+ { "123.456e11", "123.456e11", 123.456e11, 12345600000000, 0.0001e11 },
+ { "-0.0415e-12", "-0.0415e-12", -0.0415e-12, 0, 0.00001e-12 },
+ { "-0.0415e12", "-0.0415e12", -0.0415e12, -41500000000, 0.00001e12 },
+ { "-0.0415", "-0.0415", -0.0415, 0, 0.00001 },
+ { "-3.0415", "-3.0415", -3.0415, -3, 0.00001 },
+ { "123.456", "123.456", 123.456, 123, 0.0001 },
+ { "123.456e+11", "123.456e11", 123.456e+11, 12345600000000, 0.0001e+11 },
+ { "123.456e-11", "123.456e-11", 123.456e-11, 0, 0.0001e-11 },
+ { "1e-1", "1e-1", 1e-1, 0, 0.1e-1 },
+ { NULL },
+ };
+
+ for (int i = 0; successful[i].string != NULL; i++) {
+ PARCBuffer *buffer = parcBuffer_WrapCString(successful[i].string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ PARCJSONValue *expected = _parcJSONValue_NumberParser(parser);
+ assertNotNull(expected, "_parcJSONValue_NumberParser returned NULL");
+
+ long double floatValue = parcJSONValue_GetFloat(expected);
+
+ assertTrue(fabsl(floatValue - successful[i].floatValue) <= successful[i].floatTolerance,
+ "Expected %Lf actual %Lf", successful[i].floatValue, floatValue);
+
+ char *string = parcJSONValue_ToString(expected);
+ assertTrue(strcmp(successful[i].expectedString, string) == 0,
+ "Expected %s actual %s", successful[i].expectedString, string);
+ parcMemory_Deallocate((void **) &string);
+
+ int64_t integerValue = parcJSONValue_GetInteger(expected);
+ assertTrue(integerValue == (int64_t) successful[i].integerValue,
+ "Expected %" PRIi64 " actual %" PRIi64 "", (int64_t) successful[i].integerValue, integerValue);
+
+ parcJSONValue_Release(&expected);
+ parcJSONParser_Release(&parser);
+ }
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Comma)
+{
+ char *string = ", null";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_Parser(parser);
+
+ assertNull(actual, "Expected parcJSONValue_Parser to return NULL when encountering a comma");
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_CloseBracket)
+{
+ char *string = "], null";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_Parser(parser);
+
+ assertNull(actual, "Expected parcJSONValue_Parser to return NULL when encountering a ]");
+
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Null)
+{
+ char *string = " null";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_Parser(parser);
+
+ assertTrue(parcJSONValue_IsNull(actual),
+ "Expected parcJSONValue_Parser to return a Null JSON value when encountering 'null'");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_True)
+{
+ char *string = " true";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_Parser(parser);
+
+ assertTrue(parcJSONValue_IsBoolean(actual),
+ "Expected parcJSONValue_Parser to return a boolean JSON value when encountering 'true'");
+ assertTrue(parcJSONValue_GetBoolean(actual),
+ "Expected true");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_False)
+{
+ char *string = " false";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_Parser(parser);
+
+ assertTrue(parcJSONValue_IsBoolean(actual),
+ "Expected parcJSONValue_Parser to return a boolean JSON value when encountering 'false'");
+ assertFalse(parcJSONValue_GetBoolean(actual),
+ "Expected true");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_String)
+{
+ char *string = " \"string\"";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_Parser(parser);
+
+ assertTrue(parcJSONValue_IsString(actual),
+ "Expected parcJSONValue_Parser to return a string JSON value");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Array)
+{
+ char *string = " [ ]";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *value = parcJSONValue_Parser(parser);
+
+ assertTrue(parcJSONValue_IsArray(value),
+ "Expected parcJSONValue_Parser to return a array JSON value");
+
+ PARCJSONArray *array = parcJSONValue_GetArray(value);
+ assertNotNull(array, "Expected a non-null pointer to a PARCJSONArray");
+
+ parcJSONValue_Release(&value);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(JSONValueParsing, parcJSONValue_Parser_Object)
+{
+ char *string = " { }";
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ PARCJSONValue *actual = parcJSONValue_Parser(parser);
+
+ assertTrue(parcJSONValue_IsJSON(actual),
+ "Expected parcJSONValue_Parser to return a JSON object value");
+
+ parcJSONValue_Release(&actual);
+ parcJSONParser_Release(&parser);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, _parseSign_Negative);
+ LONGBOW_RUN_TEST_CASE(Static, _parseSign_NotASign);
+ LONGBOW_RUN_TEST_CASE(Static, _parseSign_Nil);
+
+ LONGBOW_RUN_TEST_CASE(Static, _parseWholeNumber);
+ LONGBOW_RUN_TEST_CASE(Static, _parseOptionalFraction);
+ LONGBOW_RUN_TEST_CASE(Static, _parseOptionalExponent);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Static, _parseSign_Negative)
+{
+ char *string = "-";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+ int sign;
+ bool result = _parseSign(parser, &sign);
+
+ assertTrue(result, "Expected true from _parseSign()");
+
+ parcJSONParser_Release(&parser);
+}
+
+LONGBOW_TEST_CASE(Static, _parseSign_NotASign)
+{
+ char *string = "asd";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+ int sign;
+ bool result = _parseSign(parser, &sign);
+
+ assertFalse(result, "Expected true from _parseSign()");
+
+ parcJSONParser_Release(&parser);
+}
+
+LONGBOW_TEST_CASE(Static, _parseSign_Nil)
+{
+ char *string = "";
+
+ PARCBuffer *buffer = parcBuffer_WrapCString(string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+ int sign;
+ bool result = _parseSign(parser, &sign);
+
+ assertTrue(result, "Expected true from _parseSign()");
+
+ parcJSONParser_Release(&parser);
+}
+
+LONGBOW_TEST_CASE(Static, _parseWholeNumber)
+{
+ struct test_values {
+ char *string;
+ long double value;
+ } successful[] = {
+ { "0", 0 },
+ { "1", 1 },
+ { "123", 123 },
+ { NULL },
+ };
+
+ for (int i = 0; successful[i].string != NULL; i++) {
+ PARCBuffer *buffer = parcBuffer_WrapCString(successful[i].string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ int64_t value = 0;
+
+ bool actual = _parseWholeNumber(parser, &value);
+
+ assertTrue(actual, "Expected true from _parseNumber()");
+ assertTrue(value == successful[i].value,
+ "Expected %Lf actual %" PRIi64 "", successful[i].value, value);
+ parcJSONParser_Release(&parser);
+ }
+}
+
+LONGBOW_TEST_CASE(Static, _parseOptionalFraction)
+{
+ struct test_values {
+ char *string;
+ long double value;
+ bool correct;
+ } successful[] = {
+ { ".0", 0, true },
+ { ".", 0, false },
+ { ".1", 1, true },
+ { "crap", 0, false },
+ { "}", 0, true },
+ { NULL },
+ };
+
+ for (int i = 0; successful[i].string != NULL; i++) {
+ PARCBuffer *buffer = parcBuffer_WrapCString(successful[i].string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ int64_t value = 0;
+ int log10OfFraction;
+
+ bool actual = _parseOptionalFraction(parser, &value, &log10OfFraction);
+
+ assertTrue(actual == successful[i].correct, "Expected true from _parseNumber()");
+ assertTrue(value == successful[i].value,
+ "Expected %Lf actual %" PRIi64 "", successful[i].value, value);
+ parcJSONParser_Release(&parser);
+ }
+}
+
+LONGBOW_TEST_CASE(Static, _parseOptionalExponent)
+{
+ struct test_values {
+ char *string;
+ long double value;
+ bool correct;
+ } successful[] = {
+ { "e", 0, false },
+ { "ex", 0, false },
+ { "e-1", -1, true },
+ { "e1", 1, true },
+ { "e+1", 1, true },
+ { "x", 0, false },
+ { NULL },
+ };
+
+ for (int i = 0; successful[i].string != NULL; i++) {
+ PARCBuffer *buffer = parcBuffer_WrapCString(successful[i].string);
+ PARCJSONParser *parser = parcJSONParser_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ int64_t value = 0;
+
+ bool actual = _parseOptionalExponent(parser, &value);
+
+ assertTrue(actual == successful[i].correct, "Expected true from _parseNumber()");
+ assertTrue(value == successful[i].value,
+ "Expected %Lf actual %" PRIi64 "", successful[i].value, value);
+ parcJSONParser_Release(&parser);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_JSONValue);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_KeyValue.c b/libparc/parc/algol/test/test_parc_KeyValue.c
new file mode 100755
index 00000000..f9440602
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_KeyValue.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/unit-test.h>
+
+#include <stdio.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_KeyValue.c"
+
+
+LONGBOW_TEST_RUNNER(parc_KeyValue)
+{
+ // 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(PARCKeyValueAsPARCObject);
+ 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(parc_KeyValue)
+{
+ 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_KeyValue)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(PARCKeyValueAsPARCObject)
+{
+ LONGBOW_RUN_TEST_CASE(PARCKeyValueAsPARCObject, parcObject_Conformance);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(PARCKeyValueAsPARCObject)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(PARCKeyValueAsPARCObject)
+{
+ 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(PARCKeyValueAsPARCObject, parcObject_Conformance)
+{
+ PARCBuffer *key = parcBuffer_WrapCString("Key_1");
+ PARCBuffer *value = parcBuffer_WrapCString("Value");
+ PARCKeyValue *inst1 = parcKeyValue_Create(key, value);
+ PARCKeyValue *inst2 = parcKeyValue_Create(key, value);
+ PARCKeyValue *inst3 = parcKeyValue_Create(key, value);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ key = parcBuffer_WrapCString("Key_0");
+ value = parcBuffer_WrapCString("Value");
+ PARCKeyValue *lesser = parcKeyValue_Create(key, value);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ key = parcBuffer_WrapCString("Key_2");
+ value = parcBuffer_WrapCString("Value");
+ PARCKeyValue *greater = parcKeyValue_Create(key, value);
+ parcBuffer_Release(&key);
+ parcBuffer_Release(&value);
+
+ parcObjectTesting_AssertObjectConformance(inst1, inst2, inst3, lesser, greater);
+
+ parcKeyValue_Release(&inst1);
+ parcKeyValue_Release(&inst2);
+ parcKeyValue_Release(&inst3);
+ parcKeyValue_Release(&lesser);
+ parcKeyValue_Release(&greater);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_GetKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_GetValue);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_EqualKeys);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_SetKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyValue_SetValue);
+}
+
+typedef struct {
+ PARCKeyValue *testKV1;
+ PARCKeyValue *testKV2;
+ PARCKeyValue *nullValue;
+ PARCBuffer *key1;
+ PARCBuffer *value1;
+ PARCBuffer *key2;
+ PARCBuffer *value2;
+} TestData;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ data->key1 = parcBuffer_WrapCString("This is key 1");
+ data->value1 = parcBuffer_WrapCString("This is value 1");
+ data->key2 = parcBuffer_WrapCString("This is key 2");
+ data->value2 = parcBuffer_WrapCString("This is value 2");
+
+ data->testKV1 = parcKeyValue_Create(data->key1, data->value1);
+ data->testKV2 = parcKeyValue_Create(data->key2, data->value2);
+
+ PARCBuffer *nullKey = parcBuffer_WrapCString("NULL KEY");
+ data->nullValue = parcKeyValue_Create(nullKey, NULL);
+ parcBuffer_Release(&nullKey);
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcBuffer_Release(&data->key1);
+ parcBuffer_Release(&data->value1);
+ parcBuffer_Release(&data->key2);
+ parcBuffer_Release(&data->value2);
+
+ parcKeyValue_Release(&data->testKV1);
+ parcKeyValue_Release(&data->testKV2);
+ parcKeyValue_Release(&data->nullValue);
+
+ 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;
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_Create)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ assertNotNull(data->testKV1, "Expect a non-NULL key value");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_Acquire)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ assertNotNull(data->testKV1, "Expect a non-NULL key value");
+
+ PARCKeyValue *kv = parcKeyValue_Acquire(data->testKV1);
+ parcKeyValue_Release(&kv);
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_GetKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ assertTrue(parcBuffer_Equals(parcKeyValue_GetKey(data->testKV1), data->key1),
+ "The key returned is not the key provided");
+
+ assertNotNull(parcKeyValue_GetKey(data->nullValue), "Expect Non-NULL key from NULL value kv");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_GetValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ assertTrue(parcBuffer_Equals(parcKeyValue_GetValue(data->testKV1), data->value1),
+ "The key returned is not the key provided");
+
+ assertNull(parcKeyValue_GetValue(data->nullValue), "Expect NULL from GetValue");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_Equals)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ bool isEqual = parcKeyValue_Equals(data->testKV1, data->testKV2);
+ assertFalse(isEqual, "Expect test key-values to not be equal");
+
+ PARCKeyValue *kv = parcKeyValue_Create(data->key1, data->value2);
+ isEqual = parcKeyValue_Equals(kv, data->testKV1) || parcKeyValue_Equals(kv, data->testKV2);
+ parcKeyValue_Release(&kv);
+ assertFalse(isEqual, "Expect test key-values to not be equal");
+
+ kv = parcKeyValue_Create(data->key1, data->value1);
+ isEqual = parcKeyValue_Equals(kv, data->testKV1) && !parcKeyValue_Equals(kv, data->testKV2);
+ parcKeyValue_Release(&kv);
+
+ assertTrue(isEqual, "Expect test key-values to be equal");
+
+ // NULL values
+ isEqual = parcKeyValue_Equals(data->testKV1, data->nullValue);
+ assertFalse(isEqual, "Expect NULL key-valuet to not be equal");
+
+ kv = parcKeyValue_Copy(data->nullValue);
+ isEqual = parcKeyValue_Equals(kv, data->nullValue);
+ assertTrue(isEqual, "Expect NULL key-valuet to not be equal");
+ parcKeyValue_Release(&kv);
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_Compare)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcKeyValue_Compare(NULL, NULL) == 0, "Expect 0 from comparing NULLs");
+ assertTrue(parcKeyValue_Compare(data->testKV1, NULL) > 0, "Expect result > 0 from comparing non-NULL to NULL");
+ assertTrue(parcKeyValue_Compare(NULL, data->testKV1) < 0, "Expect result < 0 from comparing NULL to non-NULL");
+
+ int result = parcKeyValue_Compare(data->testKV1, data->testKV2);
+ assertTrue(result < 0, "Expect compareison to be < 0");
+
+ result = parcKeyValue_Compare(data->testKV2, data->testKV1);
+ assertTrue(result > 0, "Expect compareison to be > 0");
+
+ // Mixed keys & values
+ PARCKeyValue *kv = parcKeyValue_Create(data->key1, data->value2);
+ result = parcKeyValue_Compare(kv, data->testKV1);
+ assertTrue(result == 0, "Expect comparison to be 0");
+
+ result = parcKeyValue_Compare(kv, data->testKV2);
+ assertTrue(result < 0, "Expect comparison to be < 0");
+
+ parcKeyValue_Release(&kv);
+
+ // NULL value
+ result = parcKeyValue_Compare(data->testKV1, data->nullValue);
+ assertTrue(result > 0, "Expect NULL key-value be > 0");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_HashCode)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCHashCode hash1 = parcKeyValue_HashCode(data->testKV1);
+ PARCHashCode hash2 = parcKeyValue_HashCode(data->testKV2);
+ assertFalse(hash1 == hash2, "Expect hash codes to be different");
+
+ PARCKeyValue *kv = parcKeyValue_Create(data->key1, data->value1);
+ hash2 = parcKeyValue_HashCode(kv);
+ assertTrue(hash1 == hash2, "Expect hash codes to be equal");
+ parcKeyValue_Release(&kv);
+
+ // Mixed keys & values
+ kv = parcKeyValue_Create(data->key1, data->value2);
+ hash2 = parcKeyValue_HashCode(kv);
+ assertTrue(hash1 == hash2, "Expect hash codes to be equal");
+ parcKeyValue_Release(&kv);
+
+ // NULL value
+ PARCHashCode hash = parcKeyValue_HashCode(data->nullValue);
+ assertTrue(hash != 0, "Expect NULL key-value hash to != 0");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_EqualKeys)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ assertFalse(parcKeyValue_EqualKeys(data->testKV1, data->testKV2), "Expect keys to be different");
+
+ PARCKeyValue *kv = parcKeyValue_Create(data->key1, data->value2);
+
+ assertTrue(parcKeyValue_EqualKeys(data->testKV1, kv), "Expect keys to be equal");
+
+ parcKeyValue_Release(&kv);
+
+ // NULL value
+ assertFalse(parcKeyValue_EqualKeys(data->nullValue, data->testKV1), "Expect NULL key-value hash to != 0");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_SetKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcKeyValue_SetKey(data->testKV2, data->key1);
+
+ assertTrue(parcKeyValue_EqualKeys(data->testKV1, data->testKV2),
+ "Expect kv keys to be equal after SetKey");
+
+ // NULL value
+ parcKeyValue_SetKey(data->nullValue, data->key1);
+ assertTrue(parcKeyValue_EqualKeys(data->testKV1, data->nullValue),
+ "Expect kv keys to be equal after SetKey");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_SetValue)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcKeyValue_SetValue(data->testKV2, data->value1);
+
+ assertTrue(parcBuffer_Equals(parcKeyValue_GetValue(data->testKV1),
+ parcKeyValue_GetValue(data->testKV2)),
+ "Expect kv values to be equal after SetValue");
+
+ // NULL value
+ parcKeyValue_SetValue(data->testKV2, NULL);
+ assertNull(parcKeyValue_GetValue(data->testKV2),
+ "Expect NULL for testKV2 after SetValue");
+
+ parcKeyValue_SetValue(data->nullValue, data->value1);
+ assertTrue(parcBuffer_Equals(parcKeyValue_GetValue(data->testKV1),
+ parcKeyValue_GetValue(data->nullValue)),
+ "Expect kv values to be equal after SetValue");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyValue_Copy)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCKeyValue *kv = parcKeyValue_Copy(data->testKV1);
+ assertTrue(parcKeyValue_Equals(kv, data->testKV1),
+ "Expect key-value copy to be equal to original key-value");
+
+ parcKeyValue_Release(&kv);
+
+ // NULL value
+ kv = parcKeyValue_Copy(data->nullValue);
+ assertTrue(parcKeyValue_Equals(kv, data->nullValue),
+ "Expect key-value copy to be equal to original key-value");
+
+ parcKeyValue_Release(&kv);
+}
+
+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(parc_KeyValue);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_KeyedElement.c b/libparc/parc/algol/test/test_parc_KeyedElement.c
new file mode 100755
index 00000000..a6866437
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_KeyedElement.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_KeyedElement.c"
+
+#include <LongBow/unit-test.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(parc_KeyedElement)
+{
+ // 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(parc_KeyedElement)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_KeyedElement)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyedElement_CreateDestroy);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyedElement_GetData);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyedElement_GetKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyedElement_SetData);
+}
+
+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, parcKeyedElement_CreateDestroy)
+{
+ char *key1 = "key001";
+ size_t keylen1 = 7;
+ PARCKeyedElement *keyedElement = parcKeyedElement_Create("Some data", key1, keylen1);
+ parcKeyedElement_Destroy(&keyedElement);
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyedElement_GetData)
+{
+ char *initial_data = "some data here";
+ char *key1 = "key001";
+ size_t keylen1 = 7;
+ PARCKeyedElement *keyedElement = parcKeyedElement_Create(initial_data, key1, keylen1);
+ char *data = parcKeyedElement_GetData(keyedElement);
+ assertTrue(initial_data == data, "We got different data from element");
+ parcKeyedElement_Destroy(&keyedElement);
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyedElement_GetKey)
+{
+ char *initial_data = "some data here";
+ char *key1 = "key001";
+ size_t keylen1 = 7;
+ PARCKeyedElement *keyedElement = parcKeyedElement_Create(initial_data, key1, keylen1);
+ char *thekey = parcKeyedElement_GetKey(keyedElement);
+ size_t thekeylen = parcKeyedElement_GetKeyLen(keyedElement);
+ assertTrue(keylen1 == thekeylen, "We got different key size?");
+ assertTrue(memcmp(key1, thekey, keylen1) == 0, "We got different keys?");
+ parcKeyedElement_Destroy(&keyedElement);
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyedElement_SetData)
+{
+ char *key1 = "key001";
+ size_t keylen1 = 7;
+ char *initial_data = "some data here";
+
+ PARCKeyedElement *keyedElement = parcKeyedElement_Create("Hello World", key1, keylen1);
+
+ parcKeyedElement_SetData(keyedElement, initial_data);
+ char *data = parcKeyedElement_GetData(keyedElement);
+ assertTrue(initial_data == data, "We got different data from element");
+ parcKeyedElement_Destroy(&keyedElement);
+}
+
+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(parc_KeyedElement);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_LinkedList.c b/libparc/parc/algol/test/test_parc_LinkedList.c
new file mode 100644
index 00000000..294f2ea2
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_LinkedList.c
@@ -0,0 +1,1192 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_LinkedList.c"
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_StdlibMemory.h>
+
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/testing/parc_MemoryTesting.h>
+
+LONGBOW_TEST_RUNNER(PARCLinkedList)
+{
+ // 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(Local);
+ LONGBOW_RUN_TEST_FIXTURE(AcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(PARCLinkedList)
+{
+ 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(PARCLinkedList)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(AcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcLinkedList_CreateRelease);
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcLinkedList_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease)
+{
+ bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true;
+ if (leaked) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcLinkedList_CreateRelease)
+{
+ PARCLinkedList *deque = parcLinkedList_Create();
+ assertNotNull(deque, "Expected non-null result from parcLinkedList_Create()");
+
+ assertTrue(parcLinkedList_IsValid(deque), "Expected created PARCLinkedList to be valid.");
+
+ parcLinkedList_Release(&deque);
+ assertNull(deque, "Expected parcLinkedList_Release to null the pointer");
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcLinkedList_AcquireRelease)
+{
+ PARCLinkedList *original = parcLinkedList_Create();
+ assertNotNull(original, "Expected non-null result from parcLinkedList_Create()");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcLinkedList_Acquire, original);
+
+ PARCLinkedList *reference = parcLinkedList_Acquire(original);
+ assertTrue(original == reference, "Expected the reference to be equal to the original.");
+
+ parcLinkedList_Release(&original);
+ assertNull(original, "Expected parcLinkedList_Release to null the pointer");
+
+ PARCBuffer *object = parcBuffer_Allocate(11);
+ parcLinkedList_Append(reference, object);
+ parcBuffer_Release(&object);
+
+ size_t expected = 1;
+ size_t actual = parcLinkedList_Size(reference);
+ assertTrue(expected == actual,
+ "Expected size %zd, actual %zd", expected, actual);
+ parcLinkedList_Release(&reference);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_AssertValid);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Append_One);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Append_Two);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_AppendAll);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_AppendAll_None);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateDestroy);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_GetFirst);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_GetLast);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_SetAtIndex);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Prepend_One);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Prepend_Two);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Prepend_Three);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_IsEmpty);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_GetAtIndex);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Contains_True);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Contains_False);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_RemoveFirst);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_RemoveFirst_SingleElement);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_RemoveLast);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Remove);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_RemoveNotFound);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_RemoveAtIndex);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Size);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Head);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_InsertAtIndex_HeadEmptyList);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Tail);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Middle);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_Display_NULL);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateIterator);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateIterator_Remove);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveHead);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveMiddle);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveTail);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_SetEquals_True);
+ LONGBOW_RUN_TEST_CASE(Global, parcLinkedList_SetEquals_False);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true;
+ if (leaked) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_AssertValid)
+{
+ PARCLinkedList *list = parcLinkedList_Create();
+
+ parcLinkedList_AssertValid(list);
+ parcLinkedList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Append_One)
+{
+ PARCLinkedList *list = parcLinkedList_Create();
+
+ PARCBuffer *object = parcBuffer_Allocate(11);
+ PARCLinkedList *actual = parcLinkedList_Append(list, object);
+ parcBuffer_Release(&object);
+
+ assertTrue(parcLinkedList_IsValid(list), "PARCLinkedList is invalid.");
+
+ assertTrue(list == actual, "Expected parcLinkedList_Append to return its argument.");
+ assertTrue(parcLinkedList_Size(list) == 1, "Expected size of 1, actual %zd", parcLinkedList_Size(list));
+
+ parcLinkedList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Append_Two)
+{
+ PARCLinkedList *deque = parcLinkedList_Create();
+
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+
+ parcLinkedList_Append(deque, object1);
+ PARCLinkedList *actual = parcLinkedList_Append(deque, object2);
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+
+ assertTrue(deque == actual, "Expected parcLinkedList_Append to return its argument.");
+ assertTrue(parcLinkedList_Size(deque) == 2, "Expected size of 2, actual %zd", parcLinkedList_Size(deque));
+
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_AppendAll)
+{
+ PARCLinkedList *other = parcLinkedList_Create();
+
+ for (int i = 0; i < 1000; i++) {
+ PARCBuffer *buffer = parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i);
+ parcLinkedList_Append(other, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ PARCLinkedList *list = parcLinkedList_Create();
+
+ parcLinkedList_AppendAll(list, other);
+
+ assertTrue(parcLinkedList_Equals(list, other), "Expected equal lists.");
+
+ parcLinkedList_Release(&list);
+ parcLinkedList_Release(&other);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_AppendAll_None)
+{
+ PARCLinkedList *other = parcLinkedList_Create();
+
+ PARCLinkedList *list = parcLinkedList_Create();
+
+ parcLinkedList_AppendAll(list, other);
+
+ assertTrue(parcLinkedList_Equals(list, other), "Expected equal lists.");
+
+ parcLinkedList_Release(&list);
+ parcLinkedList_Release(&other);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_CreateDestroy)
+{
+ PARCLinkedList *deque = parcLinkedList_Create();
+ assertNotNull(deque, "Expected non-null result from parcLinkedList_Create()");
+
+ parcLinkedList_Release(&deque);
+ assertNull(deque, "Expected parcLinkedList_Destroy to null the pointer");
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_HashCode)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *deque = parcLinkedList_Create();
+ parcLinkedList_Append(deque, object1);
+ parcLinkedList_Append(deque, object2);
+ parcLinkedList_Append(deque, object3);
+
+ parcLinkedList_HashCode(deque);
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_GetFirst)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *deque = parcLinkedList_Create();
+ parcLinkedList_Append(deque, object1);
+ parcLinkedList_Append(deque, object2);
+ parcLinkedList_Append(deque, object3);
+
+ PARCBuffer *actual = parcLinkedList_GetFirst(deque);
+ assertTrue(parcBuffer_Equals(object1, actual), "Order of objects in the list is wrong.");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_GetLast)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *deque = parcLinkedList_Create();
+ parcLinkedList_Append(deque, object1);
+ parcLinkedList_Append(deque, object2);
+ parcLinkedList_Append(deque, object3);
+
+ PARCBuffer *actual = parcLinkedList_GetLast(deque);
+ assertTrue(parcBuffer_Equals(object3, actual), "Order of objects in the list is wrong.");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Prepend_One)
+{
+ PARCLinkedList *deque = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCLinkedList *actual = parcLinkedList_Prepend(deque, object1);
+ parcBuffer_Release(&object1);
+
+ assertTrue(deque == actual, "Expected parcLinkedList_Append to return its argument.");
+ assertTrue(parcLinkedList_Size(deque) == 1, "Expected size of 1, actual %zd", parcLinkedList_Size(deque));
+ assertTrue(deque->head != NULL, "Expected head to be not null.");
+ assertTrue(deque->head == deque->tail, "Expected head to be equal to the tail.");
+
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Prepend_Two)
+{
+ PARCLinkedList *deque = parcLinkedList_Create();
+
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCLinkedList *actual = parcLinkedList_Prepend(deque, object1);
+ parcLinkedList_Prepend(deque, object1);
+ parcBuffer_Release(&object1);
+
+ assertTrue(deque == actual, "Expected parcLinkedList_Prepend to return its argument.");
+ assertTrue(parcLinkedList_Size(deque) == 2, "Expected size of 2, actual %zd", parcLinkedList_Size(deque));
+
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Prepend_Three)
+{
+ PARCLinkedList *deque = parcLinkedList_Create();
+
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+ parcLinkedList_Prepend(deque, object1);
+ parcLinkedList_Prepend(deque, object2);
+ PARCLinkedList *actual = parcLinkedList_Prepend(deque, object3);
+
+ assertTrue(deque == actual, "Expected parcLinkedList_Prepend to return its argument.");
+ assertTrue(parcLinkedList_Size(deque) == 3, "Expected size of 3, actual %zd", parcLinkedList_Size(deque));
+
+ PARCBuffer *peek = parcLinkedList_GetFirst(deque);
+ assertTrue(parcBuffer_Equals(object3, peek), "Order of objects failed");
+
+ peek = parcLinkedList_GetLast(deque);
+ assertTrue(parcBuffer_Equals(object1, peek), "Order of objects failed");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveFirst)
+{
+ PARCLinkedList *list = parcLinkedList_Create();
+
+ for (int i = 0; i < 1000; i++) {
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i));
+ parcLinkedList_Append(list, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ PARCBuffer *peek = parcLinkedList_RemoveFirst(list);
+ assertTrue(parcObject_GetReferenceCount(peek) == 1, "Expected reference count to be 1.");
+ assertTrue(parcBuffer_GetUint32(peek) == 0, "Objects out of order.");
+
+ parcBuffer_Release(&peek);
+ parcLinkedList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveFirst_SingleElement)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCLinkedList *deque = parcLinkedList_Create();
+ parcLinkedList_Prepend(deque, object1);
+
+ PARCBuffer *peek = parcLinkedList_RemoveFirst(deque);
+ assertTrue(parcBuffer_Equals(object1, peek),
+ "Objects out of order.");
+
+ parcBuffer_Release(&peek);
+ parcBuffer_Release(&object1);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveLast)
+{
+ PARCLinkedList *list = parcLinkedList_Create();
+
+ for (int i = 0; i < 1000; i++) {
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i));
+ parcLinkedList_Append(list, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ PARCBuffer *peek = parcLinkedList_RemoveLast(list);
+ assertTrue(parcObject_GetReferenceCount(peek) == 1, "Expected reference count to be 1.");
+ assertTrue(parcBuffer_GetUint32(peek) == 999, "Objects out of order.");
+
+ parcBuffer_Release(&peek);
+ parcLinkedList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveLast_SingleElement)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+
+ PARCLinkedList *deque = parcLinkedList_Create();
+ parcLinkedList_Prepend(deque, object1);
+
+ PARCBuffer *peek = parcLinkedList_RemoveLast(deque);
+ assertTrue(parcBuffer_Equals(object1, peek),
+ "Objects out of order.");
+
+ parcBuffer_Release(&object1);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Remove)
+{
+ PARCLinkedList *deque = parcLinkedList_Create();
+
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ parcLinkedList_Prepend(deque, object3);
+ parcLinkedList_Prepend(deque, object2);
+ parcLinkedList_Prepend(deque, object1);
+
+ bool found = parcLinkedList_Remove(deque, object2);
+ assertTrue(found, "Expected item to be found");
+ assertTrue(parcLinkedList_Size(deque) == 2, "Expected size of 2, actual %zd", parcLinkedList_Size(deque));
+
+ PARCBuffer *peek;
+ peek = parcLinkedList_RemoveFirst(deque);
+ assertTrue(parcBuffer_Equals(object1, peek), "Object1 was not first in list");
+ parcBuffer_Release(&peek);
+
+ peek = parcLinkedList_RemoveFirst(deque);
+ assertTrue(parcBuffer_Equals(object3, peek), "Object3 was not second in list");
+ parcBuffer_Release(&peek);
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveAtIndex)
+{
+ PARCLinkedList *list = parcLinkedList_Create();
+
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ parcLinkedList_Prepend(list, object3);
+ parcLinkedList_Prepend(list, object2);
+ parcLinkedList_Prepend(list, object1);
+
+ PARCBuffer *actual = parcLinkedList_RemoveAtIndex(list, 1);
+
+ assertTrue(parcBuffer_Equals(object2, actual), "Wrong object returned from parcLinkedList_RemoveAtIndex");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcBuffer_Release(&actual);
+ parcLinkedList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_RemoveNotFound)
+{
+ PARCLinkedList *deque = parcLinkedList_Create();
+
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+ PARCBuffer *object4 = parcBuffer_WrapCString("4");
+
+ parcLinkedList_Prepend(deque, object3);
+ parcLinkedList_Prepend(deque, object2);
+ parcLinkedList_Prepend(deque, object1);
+
+ bool found = parcLinkedList_Remove(deque, object4);
+ assertFalse(found, "Expected item to be not found");
+ assertTrue(parcLinkedList_Size(deque) == 3, "Expected size of 3, actual %zd", parcLinkedList_Size(deque));
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcBuffer_Release(&object4);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Size)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *deque = parcLinkedList_Create();
+ parcLinkedList_Prepend(deque, object1);
+ parcLinkedList_Prepend(deque, object2);
+ parcLinkedList_Prepend(deque, object3);
+
+ assertTrue(parcLinkedList_Size(deque) == 3,
+ "Expected 3, actual %zd", parcLinkedList_Size(deque));
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_IsEmpty)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+
+ PARCLinkedList *deque = parcLinkedList_Create();
+
+ assertTrue(parcLinkedList_IsEmpty(deque), "Expected true.");
+ parcLinkedList_Prepend(deque, object1);
+ assertFalse(parcLinkedList_IsEmpty(deque), "Expected false.");
+
+ parcBuffer_Release(&object1);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_GetAtIndex)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *deque = parcLinkedList_Create();
+ parcLinkedList_Append(deque, object1);
+ parcLinkedList_Append(deque, object2);
+ parcLinkedList_Append(deque, object3);
+
+ PARCBuffer *actual;
+ actual = parcLinkedList_GetAtIndex(deque, 0);
+ assertTrue(parcBuffer_Equals(actual, object1), "parcLinkedList_GetAtIndex failed");
+ actual = parcLinkedList_GetAtIndex(deque, 1);
+ assertTrue(parcBuffer_Equals(actual, object2), "parcLinkedList_GetAtIndex failed");
+ actual = parcLinkedList_GetAtIndex(deque, 2);
+ assertTrue(parcBuffer_Equals(actual, object3), "parcLinkedList_GetAtIndex failed");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_SetAtIndex)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *deque = parcLinkedList_Create();
+ parcLinkedList_Append(deque, object1);
+ parcLinkedList_Append(deque, object2);
+ parcLinkedList_Append(deque, object3);
+
+ PARCBuffer *newObject = parcBuffer_WrapCString("Hello");
+
+ PARCBuffer *actual = parcLinkedList_SetAtIndex(deque, 0, newObject);
+ assertTrue(parcBuffer_Equals(actual, object1), "parcLinkedList_SetAtIndex failed to return the old value.");
+ parcBuffer_Release(&actual);
+
+ actual = parcLinkedList_GetAtIndex(deque, 0);
+ assertTrue(parcBuffer_Equals(actual, newObject), "parcLinkedList_SetAtIndex failed to set the new value.");
+
+ parcBuffer_Release(&newObject);
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Contains_True)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *list = parcLinkedList_Create();
+ parcLinkedList_Append(list, object1);
+ parcLinkedList_Append(list, object2);
+ parcLinkedList_Append(list, object3);
+
+ bool actual = parcLinkedList_Contains(list, object2);
+ assertTrue(actual, "Expected parcLinkedList_Contains to return true for object in the list");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Contains_False)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *list = parcLinkedList_Create();
+ parcLinkedList_Append(list, object1);
+ parcLinkedList_Append(list, object3);
+
+ bool actual = parcLinkedList_Contains(list, object2);
+ assertFalse(actual, "Expected parcLinkedList_Contains to return false for object not in the list");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Equals)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *x = parcLinkedList_Create();
+ parcLinkedList_Append(x, object1);
+ parcLinkedList_Append(x, object2);
+ PARCLinkedList *y = parcLinkedList_Create();
+ parcLinkedList_Append(y, object1);
+ parcLinkedList_Append(y, object2);
+ PARCLinkedList *z = parcLinkedList_Create();
+ parcLinkedList_Append(z, object1);
+ parcLinkedList_Append(z, object2);
+ PARCLinkedList *u1 = parcLinkedList_Create();
+ parcLinkedList_Append(u1, object2);
+ PARCLinkedList *u2 = parcLinkedList_Create();
+ parcLinkedList_Append(u2, object2);
+ parcLinkedList_Append(u2, object3);
+
+ parcObjectTesting_AssertEqualsFunction(parcLinkedList_Equals, x, y, z, u1, u2, NULL);
+
+ parcLinkedList_Release(&x);
+ parcLinkedList_Release(&y);
+ parcLinkedList_Release(&z);
+ parcLinkedList_Release(&u1);
+ parcLinkedList_Release(&u2);
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Copy)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+ parcLinkedList_Append(x, object1);
+ parcLinkedList_Append(x, object2);
+ parcLinkedList_Append(x, object3);
+
+ PARCLinkedList *y = parcLinkedList_Copy(x);
+
+ assertTrue(parcLinkedList_Equals(x, y), "Expected the copy to be equal to the original.");
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+
+ parcLinkedList_Release(&y);
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Head)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+ PARCBuffer *object4 = parcBuffer_WrapCString("4");
+ parcLinkedList_Append(x, object1);
+ parcLinkedList_Append(x, object2);
+ parcLinkedList_Append(x, object3);
+
+ parcLinkedList_InsertAtIndex(x, 0, object4);
+
+ PARCBuffer *actual = parcLinkedList_GetAtIndex(x, 0);
+
+ assertTrue(actual == object4, "Unexpected object at index 0");
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcBuffer_Release(&object4);
+
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_InsertAtIndex_HeadEmptyList)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+ PARCBuffer *object4 = parcBuffer_WrapCString("4");
+
+ parcLinkedList_InsertAtIndex(x, 0, object4);
+ assertTrue(x->head->object == object4, "Malformed linked list node does not contain the proper object reference");
+ assertTrue(x->head == x->tail, "Expected the list head and tail to be the same for a single element list.");
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+
+ PARCBuffer *actual = parcLinkedList_GetAtIndex(x, 0);
+
+ assertTrue(actual == object4, "Unexpected object at index 0");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcBuffer_Release(&object4);
+
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Tail)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+ PARCBuffer *object4 = parcBuffer_WrapCString("4");
+ parcLinkedList_Append(x, object1);
+ parcLinkedList_Append(x, object2);
+ parcLinkedList_Append(x, object3);
+
+ parcLinkedList_InsertAtIndex(x, 3, object4);
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+
+ PARCBuffer *actual = parcLinkedList_GetAtIndex(x, 3);
+
+ assertTrue(actual == object4, "Unexpected object at index 3");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcBuffer_Release(&object4);
+
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_InsertAtIndex_Middle)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+ PARCBuffer *object4 = parcBuffer_WrapCString("4");
+ parcLinkedList_Append(x, object1);
+ parcLinkedList_Append(x, object2);
+ parcLinkedList_Append(x, object3);
+
+ parcLinkedList_InsertAtIndex(x, 1, object4);
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+
+ assertTrue(parcLinkedList_GetAtIndex(x, 0) == object1, "Unexpected object at index 1");
+ assertTrue(parcLinkedList_GetAtIndex(x, 1) == object4, "Unexpected object at index 1");
+ assertTrue(parcLinkedList_GetAtIndex(x, 2) == object2, "Unexpected object at index 1");
+ assertTrue(parcLinkedList_GetAtIndex(x, 3) == object3, "Unexpected object at index 1");
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcBuffer_Release(&object4);
+
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Display)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+ parcLinkedList_Append(x, object1);
+ parcLinkedList_Append(x, object2);
+ parcLinkedList_Append(x, object3);
+
+ parcLinkedList_Display(x, 0);
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_Display_NULL)
+{
+ parcLinkedList_Display(NULL, 0);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_CreateIterator)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+
+ uint32_t expectedCount = 10;
+ for (uint32_t i = 0; i < expectedCount; i++) {
+ PARCBuffer *object = parcBuffer_Allocate(sizeof(int));
+ parcBuffer_PutUint32(object, i);
+ parcBuffer_Flip(object);
+ parcLinkedList_Append(x, object);
+ parcBuffer_Release(&object);
+ }
+
+ PARCIterator *iterator = parcLinkedList_CreateIterator(x);
+ uint32_t expected = 0;
+ while (parcIterator_HasNext(iterator)) {
+ PARCBuffer *buffer = (PARCBuffer *) parcIterator_Next(iterator);
+ uint32_t actual = parcBuffer_GetUint32(buffer);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+ expected++;
+ }
+ parcIterator_Release(&iterator);
+
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_CreateIterator_Remove)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ for (size_t i = 0; i < 5; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutUint64(buffer, i);
+ parcBuffer_Flip(buffer);
+ parcLinkedList_Append(x, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+
+ PARCIterator *iterator = parcLinkedList_CreateIterator(x);
+ size_t expected = 0;
+ while (parcIterator_HasNext(iterator)) {
+ size_t actual = parcBuffer_GetUint64(parcIterator_Next(iterator));
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ parcIterator_Remove(iterator);
+ expected++;
+ }
+ parcIterator_Release(&iterator);
+
+ iterator = parcLinkedList_CreateIterator(x);
+ assertFalse(parcIterator_HasNext(iterator), "Expected an interator on an empty list to not HaveNext");
+ parcIterator_Release(&iterator);
+
+ assertTrue(parcLinkedList_Size(x) == 0, "List is not empty.");
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveHead)
+{
+ size_t listSize = 5;
+
+ PARCLinkedList *x = parcLinkedList_Create();
+ for (size_t i = 0; i < listSize; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutUint64(buffer, i);
+ parcBuffer_Flip(buffer);
+ parcLinkedList_Append(x, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+ parcLinkedList_Display(x, 0);
+
+ PARCIterator *iterator = parcLinkedList_CreateIterator(x);
+ if (parcIterator_HasNext(iterator)) {
+ PARCBuffer *buffer = (PARCBuffer *) parcIterator_Next(iterator);
+ size_t actual = parcBuffer_GetUint64(buffer);
+ assertTrue(actual == 0, "Expected %d, actual %zd", 0, actual);
+ parcIterator_Remove(iterator);
+ }
+ parcIterator_Release(&iterator);
+
+ iterator = parcLinkedList_CreateIterator(x);
+ assertTrue(parcIterator_HasNext(iterator), "Expected an interator on a non-empty list to HaveNext");
+ parcIterator_Release(&iterator);
+
+ assertTrue(parcLinkedList_Size(x) == listSize - 1, "Expected the list to be %zd, actual %zd", listSize - 1, parcLinkedList_Size(x));
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveMiddle)
+{
+ size_t listSize = 5;
+
+ PARCLinkedList *x = parcLinkedList_Create();
+ for (size_t i = 0; i < listSize; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutUint64(buffer, i);
+ parcBuffer_Flip(buffer);
+ parcLinkedList_Append(x, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+ assertTrue(parcLinkedList_Size(x) == listSize, "Expected the list to be %zd, actual %zd", listSize, parcLinkedList_Size(x));
+
+
+ PARCIterator *iterator = parcLinkedList_CreateIterator(x);
+ for (size_t i = 0; i <= listSize / 2; i++) {
+ if (parcIterator_HasNext(iterator)) {
+ parcIterator_Next(iterator);
+ }
+ }
+ parcIterator_Remove(iterator);
+
+ parcIterator_Release(&iterator);
+
+
+ iterator = parcLinkedList_CreateIterator(x);
+ size_t expected = 0;
+ while (parcIterator_HasNext(iterator)) {
+ if (expected != (listSize / 2)) {
+ size_t actual = parcBuffer_GetUint64(parcIterator_Next(iterator));
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ }
+ expected++;
+ }
+ parcIterator_Release(&iterator);
+
+ assertTrue(parcLinkedList_Size(x) == listSize - 1, "Expected the list to be %zd, actual %zd", listSize - 1, parcLinkedList_Size(x));
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_CreateIterator_RemoveTail)
+{
+ size_t listSize = 5;
+
+ PARCLinkedList *x = parcLinkedList_Create();
+ for (size_t i = 0; i < listSize; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcBuffer_PutUint64(buffer, i);
+ parcBuffer_Flip(buffer);
+ parcLinkedList_Append(x, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+ assertTrue(parcLinkedList_Size(x) == listSize, "Expected the list to be %zd, actual %zd", listSize, parcLinkedList_Size(x));
+
+ PARCIterator *iterator = parcLinkedList_CreateIterator(x);
+ for (size_t i = 0; i < listSize; i++) {
+ if (parcIterator_HasNext(iterator)) {
+ parcIterator_Next(iterator);
+ }
+ }
+ parcIterator_Remove(iterator);
+
+ parcIterator_Release(&iterator);
+
+ assertTrue(parcLinkedList_Size(x) == listSize - 1, "Expected the list to be %zd, actual %zd", listSize - 1, parcLinkedList_Size(x));
+
+
+ iterator = parcLinkedList_CreateIterator(x);
+ size_t expected = 0;
+ while (parcIterator_HasNext(iterator)) {
+ size_t actual = parcBuffer_GetUint64(parcIterator_Next(iterator));
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ expected++;
+ }
+ parcIterator_Release(&iterator);
+
+ assertTrue(parcLinkedList_IsValid(x), "PARCLinkedList is invalid.");
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_SetEquals_True)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *x = parcLinkedList_Create();
+ parcLinkedList_Append(x, object1);
+ parcLinkedList_Append(x, object2);
+ PARCLinkedList *y = parcLinkedList_Create();
+ parcLinkedList_Append(y, object2);
+ parcLinkedList_Append(y, object1);
+
+ PARCLinkedList *u1 = parcLinkedList_Create();
+ parcLinkedList_Append(u1, object2);
+
+ PARCLinkedList *u2 = parcLinkedList_Create();
+ parcLinkedList_Append(u2, object2);
+ parcLinkedList_Append(u2, object3);
+
+ assertTrue(parcLinkedList_SetEquals(x, y), "Expected to lists with the same elements to be equal regarless of order.");
+
+ parcLinkedList_Release(&x);
+ parcLinkedList_Release(&y);
+ parcLinkedList_Release(&u1);
+ parcLinkedList_Release(&u2);
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+}
+
+LONGBOW_TEST_CASE(Global, parcLinkedList_SetEquals_False)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCLinkedList *x = parcLinkedList_Create();
+ parcLinkedList_Append(x, object1);
+ parcLinkedList_Append(x, object2);
+
+ PARCLinkedList *u1 = parcLinkedList_Create();
+ parcLinkedList_Append(u1, object2);
+
+ PARCLinkedList *u2 = parcLinkedList_Create();
+ parcLinkedList_Append(u2, object2);
+ parcLinkedList_Append(u2, object3);
+
+ assertFalse(parcLinkedList_SetEquals(x, u1), "Expected to lists without the same elements to be equal regarless of order.");
+
+ parcLinkedList_Release(&x);
+ parcLinkedList_Release(&u1);
+ parcLinkedList_Release(&u2);
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _parcLinkedListNode_Create);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ bool leaked = parcMemoryTesting_ExpectedOutstanding(0, "%s leaks memory \n", longBowTestCase_GetName(testCase)) != true;
+ if (leaked) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, _parcLinkedListNode_Create)
+{
+ PARCBuffer *object = parcBuffer_Allocate(10);
+ struct parc_linkedlist_node *previous = NULL;
+ struct parc_linkedlist_node *next = NULL;
+
+ struct parc_linkedlist_node *actual = _parcLinkedListNode_Create(object, previous, next);
+ parcBuffer_Release(&object);
+ _parcLinkedListNode_Destroy(NULL, &actual);
+}
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcLinkedList_Append);
+ LONGBOW_RUN_TEST_CASE(Performance, parcLinkedList_N2);
+ LONGBOW_RUN_TEST_CASE(Performance, parcLinkedList_CreateIterator);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ parcMemory_SetInterface(&PARCStdlibMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ 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(Performance, parcLinkedList_Append)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+
+ for (size_t i = 0; i < 100000; i++) {
+ parcLinkedList_Append(x, object1);
+ }
+
+ parcBuffer_Release(&object1);
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Performance, parcLinkedList_N2)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+
+ for (size_t i = 0; i < 100000; i++) {
+ parcLinkedList_Append(x, object1);
+ }
+
+ for (size_t expected = 0; expected < parcLinkedList_Size(x); expected++) {
+ PARCBuffer *actual = (PARCBuffer *) parcLinkedList_GetAtIndex(x, expected);
+ assertTrue(parcBuffer_Equals(object1, actual), "Mismatched value in the list.");
+ }
+
+ parcBuffer_Release(&object1);
+
+ parcLinkedList_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Performance, parcLinkedList_CreateIterator)
+{
+ PARCLinkedList *x = parcLinkedList_Create();
+
+ uint32_t expectedCount = 100000;
+ for (uint32_t i = 0; i < expectedCount; i++) {
+ PARCBuffer *object = parcBuffer_Allocate(sizeof(int));
+ parcBuffer_PutUint32(object, i);
+ parcBuffer_Flip(object);
+ parcLinkedList_Append(x, object);
+ parcBuffer_Release(&object);
+ }
+
+ PARCIterator *iterator = parcLinkedList_CreateIterator(x);
+ uint32_t expected = 0;
+ while (parcIterator_HasNext(iterator)) {
+ PARCBuffer *buffer = (PARCBuffer *) parcIterator_Next(iterator);
+ uint32_t actual = parcBuffer_GetUint32(buffer);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+ expected++;
+ }
+ parcIterator_Release(&iterator);
+
+ parcLinkedList_Release(&x);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARCLinkedList);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_List.c b/libparc/parc/algol/test/test_parc_List.c
new file mode 100644
index 00000000..59a7d136
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_List.c
@@ -0,0 +1,872 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_List.c"
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_LinkedList.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(PARCList)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(PARCList);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+// LONGBOW_RUN_TEST_FIXTURE(Errors);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(PARCList)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(PARCList)
+{
+ 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;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Add);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_AddAll);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcList_Release);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Equals_Contract);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Equals_Contract_Deep);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_FromInitialCapacity);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Get);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_New);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Length);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Remove_AtIndex_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Remove_AtIndex);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_Remove_AtIndex_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_InsertAtIndex);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_InsertAtIndex_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_InsertAtIndex_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_InsertAtIndex_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARCList_IsEmpty);
+}
+
+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, PARCList_Add)
+{
+ PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList);
+
+ parcList_Add(list, 0);
+ size_t actual = parcList_Size(list);
+ assertTrue(1 == actual, "Expected=%d, actual=%zu", 1, actual);
+
+ parcList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_AddAll)
+{
+ PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList);
+
+ void *elements[] = {
+ strdup("a"),
+ strdup("b"),
+ strdup("c"),
+ };
+
+ parcList_AddAll(list, 3, elements);
+ size_t actual = parcList_Size(list);
+
+ assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual);
+
+ parcList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Copy)
+{
+ char *a = strdup("apple");
+ char *b = strdup("bananna");
+ char *c = strdup("cherry");
+
+ PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList);
+
+ parcList_Add(list, a);
+ parcList_Add(list, b);
+ parcList_Add(list, c);
+
+ parcList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, parcList_Release)
+{
+ PARCList *list = parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction), PARCArrayListAsPARCList);
+
+ parcList_Release(&list);
+ assertNull(list, "Expected null.");
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Equals_Empty)
+{
+ PARCArrayList *a = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ PARCArrayList *b = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ assertTrue(parcArrayList_Equals(a, b), "Equal values were expected to be equal");
+
+ parcArrayList_Destroy(&a);
+ parcArrayList_Destroy(&b);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Equals_Same)
+{
+ PARCArrayList *a = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ assertTrue(parcArrayList_Equals(a, a), "Expected the same array list to be equal to itself.");
+
+ parcArrayList_Destroy(&a);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Equals_Contract)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+ char d[] = "potato";
+
+ PARCArrayList *x = parcArrayList_Create(NULL);
+ parcArrayList_Add(x, a);
+ parcArrayList_Add(x, b);
+ parcArrayList_Add(x, c);
+
+ PARCArrayList *y = parcArrayList_Create(NULL);
+ parcArrayList_Add(y, a);
+ parcArrayList_Add(y, b);
+ parcArrayList_Add(y, c);
+
+ PARCArrayList *z = parcArrayList_Create(NULL);
+ parcArrayList_Add(z, a);
+ parcArrayList_Add(z, b);
+ parcArrayList_Add(z, c);
+
+ PARCArrayList *u1 = parcArrayList_Create(NULL);
+ parcArrayList_Add(u1, a);
+ parcArrayList_Add(u1, b);
+
+ PARCArrayList *u2 = parcArrayList_Create(NULL);
+ parcArrayList_Add(u1, a);
+ parcArrayList_Add(u2, b);
+ parcArrayList_Add(u2, c);
+ parcArrayList_Add(u2, c);
+
+ PARCArrayList *u3 = parcArrayList_Create(NULL);
+ parcArrayList_Add(u3, a);
+ parcArrayList_Add(u3, b);
+ parcArrayList_Add(u3, d);
+
+ parcObjectTesting_AssertEqualsFunction(parcArrayList_Equals, x, y, z, u1, u2, u3);
+
+ parcArrayList_Destroy(&x);
+ parcArrayList_Destroy(&y);
+ parcArrayList_Destroy(&z);
+ parcArrayList_Destroy(&u1);
+ parcArrayList_Destroy(&u2);
+ parcArrayList_Destroy(&u3);
+}
+
+static bool
+stringEquals(void *x, void *y)
+{
+ return strcmp((char *) x, (char *) y) == 0;
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Equals_Contract_Deep)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+ char d[] = "potato";
+
+ PARCArrayList *x = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(x, a);
+ parcArrayList_Add(x, b);
+ parcArrayList_Add(x, c);
+
+ PARCArrayList *y = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(y, a);
+ parcArrayList_Add(y, b);
+ parcArrayList_Add(y, c);
+
+ PARCArrayList *z = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(z, a);
+ parcArrayList_Add(z, b);
+ parcArrayList_Add(z, c);
+
+ PARCArrayList *u1 = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(u1, a);
+ parcArrayList_Add(u1, b);
+
+ PARCArrayList *u2 = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(u2, a);
+ parcArrayList_Add(u2, b);
+ parcArrayList_Add(u2, c);
+ parcArrayList_Add(u2, c);
+
+ PARCArrayList *u3 = parcArrayList_Create_Capacity(stringEquals, NULL, 0);
+ parcArrayList_Add(u3, a);
+ parcArrayList_Add(u3, b);
+ parcArrayList_Add(u3, d);
+
+ parcObjectTesting_AssertEqualsFunction(parcArrayList_Equals, x, y, z, u1, u2, u3);
+
+ parcArrayList_Destroy(&x);
+ parcArrayList_Destroy(&y);
+ parcArrayList_Destroy(&z);
+ parcArrayList_Destroy(&u1);
+ parcArrayList_Destroy(&u2);
+ parcArrayList_Destroy(&u3);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_FromInitialCapacity)
+{
+ PARCArrayList *array = parcArrayList_Create_Capacity(NULL, parcArrayList_StdlibFreeFunction, 10);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(0 == actual, "Expected=%d, actual=%zu", 0, actual);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Get)
+{
+ PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+
+ char *expected = strdup("Hello World");
+ parcArrayList_Add(array, expected);
+
+ char *actual = parcArrayList_Get(array, 0);
+
+ assertTrue(expected == actual, "Expected=%p, actual=%p", (void *) expected, (void *) actual);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_New)
+{
+ PARCArrayList *array = parcArrayList_Create(parcArrayList_StdlibFreeFunction);
+ size_t size = parcArrayList_Size(array);
+ assertTrue(0 == size, "Expected %d actual=%zd", 0, size);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Length)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, 0);
+
+ size_t size = parcArrayList_Size(array);
+ assertTrue(1 == size, "Expected %d actual=%zd", 1, size);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_IsEmpty)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ assertTrue(parcArrayList_IsEmpty(array), "Expected a new array to be empty.");
+
+ parcArrayList_Add(array, 0);
+ assertFalse(parcArrayList_IsEmpty(array), "Expected an array with more than zero elements to be empty.");
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_InsertAtIndex)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ parcArrayList_Add(array, (void *) 1);
+ parcArrayList_Add(array, (void *) 2);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual);
+
+ parcArrayList_InsertAtIndex(array, 1, (void *) 3);
+
+ actual = parcArrayList_Size(array);
+ assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual);
+
+ void *element0 = parcArrayList_Get(array, 0);
+ assertTrue(element0 == (void *) 1, "Element 1 moved?");
+
+ void *element1 = parcArrayList_Get(array, 1);
+ assertTrue(element1 == (void *) 3, "Element 1 moved?");
+
+ void *element2 = parcArrayList_Get(array, 2);
+ assertTrue(element2 == (void *) 2, "Element 1 moved?");
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_InsertAtIndex_Empty)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ parcArrayList_InsertAtIndex(array, 0, (void *) 3);
+
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(1 == actual, "Expected=%d, actual=%zu", 1, actual);
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_InsertAtIndex_First)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ parcArrayList_Add(array, (void *) 1);
+ parcArrayList_InsertAtIndex(array, 0, (void *) 2);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual);
+
+ void *element0 = parcArrayList_Get(array, 0);
+ assertTrue(element0 == (void *) 2, "Element 1 moved?");
+
+ void *element1 = parcArrayList_Get(array, 1);
+ assertTrue(element1 == (void *) 1, "Element 1 moved?");
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_InsertAtIndex_Last)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ parcArrayList_Add(array, (void *) 1);
+ parcArrayList_Add(array, (void *) 2);
+ size_t actual = parcArrayList_Size(array);
+
+ assertTrue(2 == actual, "Expected=%d, actual=%zu", 2, actual);
+
+ parcArrayList_InsertAtIndex(array, 2, (void *) 3);
+
+ actual = parcArrayList_Size(array);
+ assertTrue(3 == actual, "Expected=%d, actual=%zu", 3, actual);
+
+ void *element0 = parcArrayList_Get(array, 0);
+ assertTrue(element0 == (void *) 1, "Element 1 moved?");
+
+ void *element1 = parcArrayList_Get(array, 1);
+ assertTrue(element1 == (void *) 2, "Element 1 moved?");
+
+ void *element2 = parcArrayList_Get(array, 2);
+ assertTrue(element2 == (void *) 3, "Element 1 moved?");
+
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Remove_AtIndex_First)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, b);
+ parcArrayList_Add(expected, c);
+
+ void *removedElement = parcArrayList_RemoveAtIndex(array, 0);
+
+ assertTrue(removedElement == a, "Expected ");
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_Remove_AtIndex)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, a);
+ parcArrayList_Add(expected, c);
+
+ void *removedElement = parcArrayList_RemoveAtIndex(array, 1);
+
+ assertTrue(removedElement == b, "Expected ");
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+
+LONGBOW_TEST_CASE(Global, PARCList_Remove_AtIndex_Last)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, a);
+ parcArrayList_Add(expected, b);
+
+ void *removedElement = parcArrayList_RemoveAtIndex(array, 2);
+
+ assertTrue(removedElement == c, "Expected ");
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex_First)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, b);
+ parcArrayList_Add(expected, c);
+
+ parcArrayList_RemoveAndDestroyAtIndex(array, 0);
+
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, a);
+ parcArrayList_Add(expected, c);
+
+ parcArrayList_RemoveAndDestroyAtIndex(array, 1);
+
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(Global, PARCList_RemoveAndDestroy_AtIndex_Last)
+{
+ char a[] = "apple";
+ char b[] = "bananna";
+ char c[] = "cherry";
+
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, a);
+ parcArrayList_Add(array, b);
+ parcArrayList_Add(array, c);
+
+ PARCArrayList *expected = parcArrayList_Create(NULL);
+ parcArrayList_Add(expected, a);
+ parcArrayList_Add(expected, b);
+
+ parcArrayList_RemoveAndDestroyAtIndex(array, 2);
+
+ assertTrue(parcArrayList_Equals(expected, array), "Expected ");
+
+ parcArrayList_Destroy(&expected);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, PARCList_InsertAtIndex_OutOfCapacity);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+
+ longBowTestCase_SetClipBoardData(testCase, array);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ PARCArrayList *array = longBowTestCase_GetClipBoardData(testCase);
+ parcArrayList_Destroy(&array);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Errors %s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, PARCList_InsertAtIndex_OutOfCapacity, .event = &LongBowAssertEvent)
+{
+ PARCArrayList *array = longBowTestCase_GetClipBoardData(testCase);
+
+ parcArrayList_Add(array, (void *) 1);
+ parcArrayList_Add(array, (void *) 2);
+
+ parcArrayList_InsertAtIndex(array, 200, (void *) 3);
+}
+
+
+LONGBOW_TEST_FIXTURE(PARCList)
+{
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_Add);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_AddCollection);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_AddCollectionAtIndex);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_Contains);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_ContainsCollection);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_Equals);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_IsEmpty);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_GetAtIndex);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_Remove);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_RemoveCollection);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_RetainCollection);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_HashCode);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_IndexOf);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_LastIndexOf);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_Copy);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_Clear);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_Destroy);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_RemoveAtIndex);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_SetAtIndex);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_Size);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_SubList);
+ LONGBOW_RUN_TEST_CASE(PARCList, parcList_ToArray);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(PARCList)
+{
+ longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding());
+ longBowTestCase_Set(testCase, "linkedList", parcLinkedList_Create());
+ longBowTestCase_Set(testCase, "list", parcLinkedList_AsPARCList(longBowTestCase_Get(testCase, "linkedList")));
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(PARCList)
+{
+ PARCLinkedList *linkedList = longBowTestCase_Get(testCase, "linkedList");
+ parcLinkedList_Release(&linkedList);
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+ parcList_Release(&list);
+
+ int initialAllocations = longBowTestCase_GetInt(testCase, "initalAllocations");
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+//#include "test_parc_List_modular.c"
+
+LONGBOW_TEST_CASE(PARCList, parcList_Add)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 1));
+ parcList_Add(list, buffer);
+ parcBuffer_Release(&buffer);
+
+ size_t actual = parcList_Size(list);
+ assertTrue(1 == actual, "Expected=%d, actual=%zu", 1, actual);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_AddCollection)
+{
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_AddCollectionAtIndex)
+{
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_Contains)
+{
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_ContainsCollection)
+{
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_Equals)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+ PARCList *copy = parcList_Copy(list);
+
+ assertTrue(parcList_Equals(list, copy), "Expected copy to be equal to the original.");
+
+ parcList_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_IsEmpty)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+ assertTrue(parcList_IsEmpty(list), "Expected list to be empty.");
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_GetAtIndex)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+
+ for (int i = 0; i < 1000; i++) {
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i));
+ parcList_Add(list, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ uint32_t actual = parcBuffer_GetUint32(parcList_GetAtIndex(list, 0));
+
+ assertTrue(actual == 0, "Expected %u, actual %u\n", 0, actual);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_Remove)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 1));
+ parcList_Add(list, buffer);
+ parcBuffer_Release(&buffer);
+
+ buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 1));
+
+ bool actual = parcList_Remove(list, buffer);
+ assertTrue(actual, "Expected element to have been found and removed.");
+
+ parcBuffer_Release(&buffer);
+
+ buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 3));
+
+ actual = parcList_Remove(list, buffer);
+ assertFalse(actual, "Expected element to have not been found and removed.");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_RemoveCollection)
+{
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_RetainCollection)
+{
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_HashCode)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+ parcList_HashCode(list);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_IndexOf)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+
+ for (int i = 0; i < 1000; i++) {
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i));
+ parcList_Add(list, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ uint32_t expected = 10;
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 10));
+ size_t actual = parcList_IndexOf(list, buffer);
+
+ parcBuffer_Release(&buffer);
+
+ assertTrue(expected == actual, "Expected %u, actual %zu", expected, actual);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_LastIndexOf)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+
+ for (int i = 0; i < 1000; i++) {
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 1));
+ parcList_Add(list, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ uint32_t expected = 999;
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), 1));
+ size_t actual = parcList_LastIndexOf(list, buffer);
+
+ parcBuffer_Release(&buffer);
+
+ assertTrue(expected == actual, "Expected %u, actual %zu", expected, actual);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_Copy)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+ PARCList *copy = parcList_Copy(list);
+
+ assertTrue(parcList_Equals(list, copy), "Expected copy to be equal to the original.");
+
+ parcList_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_Clear)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+ parcList_Clear(list);
+
+ assertTrue(parcList_IsEmpty(list), "Expected list to be empty.");
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_Destroy)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+ PARCList *copy = parcList_Copy(list);
+
+ parcList_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_RemoveAtIndex)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+
+ for (int i = 0; i < 1000; i++) {
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i));
+ parcList_Add(list, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ PARCBuffer *buffer = parcList_RemoveAtIndex(list, 0);
+ uint32_t actual = parcBuffer_GetUint32(buffer);
+ assertTrue(actual == 0, "Expected buffer 0.");
+
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_SetAtIndex)
+{
+ PARCList *list = longBowTestCase_Get(testCase, "list");
+
+ for (int i = 0; i < 1000; i++) {
+ PARCBuffer *buffer = parcBuffer_Flip(parcBuffer_PutUint32(parcBuffer_Allocate(sizeof(int)), i));
+ parcList_Add(list, buffer);
+ parcBuffer_Release(&buffer);
+ }
+
+ PARCBuffer *buffer = parcBuffer_WrapCString("1");
+
+ PARCBuffer *oldValue = parcList_SetAtIndex(list, 50, buffer);
+
+ PARCBuffer *actual = parcList_GetAtIndex(list, 50);
+ assertTrue(parcBuffer_Equals(buffer, actual), "parcList_SetAtIndex set the wrong location.");
+ parcBuffer_Release(&buffer);
+ parcBuffer_Release(&oldValue);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_Size)
+{
+ PARCArrayList *array = parcArrayList_Create(NULL);
+ parcArrayList_Add(array, 0);
+
+ size_t size = parcArrayList_Size(array);
+ assertTrue(1 == size, "Expected %d actual=%zd", 1, size);
+ parcArrayList_Destroy(&array);
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_SubList)
+{
+}
+
+LONGBOW_TEST_CASE(PARCList, parcList_ToArray)
+{
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARCList);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Memory.c b/libparc/parc/algol/test/test_parc_Memory.c
new file mode 100755
index 00000000..5fb18ce3
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Memory.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 <config.h>
+#include <stdio.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 "../parc_Memory.c"
+
+LONGBOW_TEST_RUNNER(parc_Memory)
+{
+ // 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(Static);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Memory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Memory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_RoundUpToMultiple);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_RoundUpToCacheLine);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_Allocate);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_AllocateAndClear);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_MemAlign);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_Reallocate);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_StringDuplicate);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_Outstanding);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_SetInterface);
+ LONGBOW_RUN_TEST_CASE(Global, parcMemory_Format);
+}
+
+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, parcMemory_RoundUpToMultiple)
+{
+ size_t actual = parcMemory_RoundUpToMultiple(14, 12);
+ assertTrue((actual % 12) == 0, "Expected %zd to be a multiple of %d", actual, 12);
+ assertTrue(24 == actual, "Expected 24, actual %zd", actual);
+
+ actual = parcMemory_RoundUpToMultiple(14, 20);
+ assertTrue((actual % 20) == 0, "Expected %zd to be a multiple of %d", actual, 20);
+ assertTrue(20 == actual, "Expected 20, actual %zd", actual);
+
+ actual = parcMemory_RoundUpToMultiple(20, 20);
+ assertTrue((actual % 20) == 0, "Expected %zd to be a multiple of %d", actual, 20);
+ assertTrue(20 == actual, "Expected 20, actual %zd", actual);
+
+ actual = parcMemory_RoundUpToMultiple(0, 20);
+ assertTrue((actual % 20) == 0, "Expected %zd to be a multiple of %d", actual, 20);
+ assertTrue(20 == actual, "Expected 20, actual %zd", actual);
+
+ actual = parcMemory_RoundUpToMultiple(8, 0);
+ assertTrue(actual == 8, "Expected %d, actual %zd", 8, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_RoundUpToCacheLine)
+{
+ size_t actual = parcMemory_RoundUpToCacheLine(LEVEL1_DCACHE_LINESIZE - 1);
+ assertTrue((actual % LEVEL1_DCACHE_LINESIZE) == 0,
+ "Expected %zd to be a multiple of %d", actual, LEVEL1_DCACHE_LINESIZE);
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_Allocate)
+{
+ void *pointer;
+ pointer = parcMemory_Allocate(sizeof(int));
+ assertNotNull(pointer, "Expected pointer to not be NULL");
+
+ parcMemory_Deallocate(&pointer);
+ assertNull(pointer, "Expected pointer to not be NULL");
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_MemAlign)
+{
+ void *pointer;
+ int actual = parcMemory_MemAlign(&pointer, sizeof(void *), sizeof(int));
+ assertTrue(actual == 0, "Expected successful return value.");
+ assertNotNull(pointer, "Expected pointer to not be NULL");
+
+ parcMemory_Deallocate(&pointer);
+ assertNull(pointer, "Expected pointer to not be NULL");
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_Reallocate)
+{
+ void *pointer;
+ int actual = parcMemory_MemAlign(&pointer, sizeof(void *), sizeof(int));
+ assertTrue(actual == 0, "Expected successful return value.");
+
+ pointer = parcMemory_Reallocate(pointer, sizeof(int) * 2);
+ assertNotNull(pointer, "Expected pointer to not be NULL");
+
+ parcMemory_Deallocate(&pointer);
+ assertNull(pointer, "Expected pointer to not be NULL");
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_AllocateAndClear)
+{
+ void *pointer;
+ pointer = parcMemory_AllocateAndClear(sizeof(int));
+ assertNotNull(pointer, "Expected pointer to not be NULL");
+
+ for (int i = 0; i < sizeof(int); i++) {
+ assertTrue(((char *) pointer)[i] == 0, "Expected cell to be zero.");
+ }
+
+ parcMemory_Deallocate(&pointer);
+ assertNull(pointer, "Expected pointer to not be NULL");
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_StringDuplicate)
+{
+ char *expected = "Hello";
+
+ char *actual = parcMemory_StringDuplicate(expected, strlen(expected));
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_Outstanding)
+{
+ void *pointer;
+ pointer = parcMemory_Allocate(sizeof(int));
+
+ size_t expected = 1;
+ size_t actual = parcMemory_Outstanding();
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+
+ parcMemory_Deallocate(&pointer);
+
+ expected = 0;
+ actual = parcMemory_Outstanding();
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_SetInterface)
+{
+ const PARCMemoryInterface *old = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ parcMemory_SetInterface(old);
+}
+
+LONGBOW_TEST_CASE(Global, parcMemory_Format)
+{
+ char *expected = "Hello World";
+ char *actual = parcMemory_Format("Hello %s", "World");
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate(&actual);
+}
+
+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(parc_Memory);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Network.c b/libparc/parc/algol/test/test_parc_Network.c
new file mode 100755
index 00000000..864fe25d
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Network.c
@@ -0,0 +1,668 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_Network.c"
+
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <sys/un.h>
+
+LONGBOW_TEST_RUNNER(parc_Networking)
+{
+ // 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(Local);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Networking)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Networking)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockInet4AddressAny);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockInet4Address_BuildString);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockInet6Address_BuildString);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_BuildString_dashes);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_BuildString_colons);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_Inet4Equals);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_dashes);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_colons);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_dots);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseLinkAddress_BadScheme);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_BadLink);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_BadMixOfDashesAndDots);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_BadMixOfDotsAndDashes);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_BadSpecification);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseInet4Address);
+
+ LONGBOW_RUN_TEST_CASE(Global, parseMAC48Address);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons_TooShort);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons_Garbage);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseMAC48Address);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_ParseMAC48Address_TooShort);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockAddress_ipv4);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockAddress_ipv6);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_SockAddress_hostname);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_LOCAL);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_INET4);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_INET6);
+ LONGBOW_RUN_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_IPX);
+}
+
+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, parcNetwork_SockInet4AddressAny)
+{
+ struct sockaddr_in *test_sock = parcNetwork_SockInet4AddressAny();
+
+ assertNotNull(test_sock, "Expected a not null pointer\n");
+ assertTrue(test_sock->sin_family == AF_INET, "Expecting sin_family to be AF_INET\n");
+ assertTrue(test_sock->sin_addr.s_addr == INADDR_ANY, "Expecting sin_addr.s_addr to be set to INADDR_ANY\n");
+#if defined(SIN6_LEN)
+ assertTrue(test_sock->sin_len == sizeof(struct sockaddr_in), "Expecting sockaddr.sin_len to be %zu not %hhu\n",
+ sizeof(struct sockaddr_in), test_sock->sin_len);
+#endif
+
+ parcMemory_Deallocate((void **) &test_sock);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_SockInet4Address_BuildString)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ struct sockaddr_in *address = parcNetwork_SockInet4Address("127.0.0.1", 1234);
+#if defined(SIN6_LEN)
+ assertTrue(address->sin_len == sizeof(struct sockaddr_in), "Expecting sockaddr.sin_len to be %zu not %hhu\n",
+ sizeof(struct sockaddr_in), address->sin_len);
+#endif
+ parcNetwork_SockInet4Address_BuildString(address, composer);
+
+ char *expected = "inet4://127.0.0.1:1234";
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcMemory_Deallocate((void **) &address);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_SockInet6Address_BuildString)
+{
+ struct sockaddr_in6 *address = parcNetwork_SockInet6Address("2001:720:1500:1::a100", 1234, 0, 1);
+#if defined(SIN6_LEN)
+ assertTrue(address->sin6_len == sizeof(struct sockaddr_in6), "Expecting sockaddr.sin6_len to be %zu not %hhu\n",
+ sizeof(struct sockaddr_in6), address->sin6_len);
+#endif
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcNetwork_SockInet6Address_BuildString(address, composer);
+
+ char *expected = "inet6://[2001:720:1500:1::a100%1]:1234";
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcMemory_Deallocate((void **) &address);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_LinkAddress_BuildString_dashes)
+{
+ char *expected = "link://01-23-45-67-89-ab";
+
+ PARCBuffer *address = parcNetwork_ParseLinkAddress(expected);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ parcNetwork_LinkAddress_BuildString((unsigned char *) parcBuffer_Overlay(address, 0), parcBuffer_Remaining(address), composer);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBufferComposer_Release(&composer);
+ parcBuffer_Release(&address);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_LinkAddress_BuildString_colons)
+{
+ char *expected = "link://01-23-45-67-89-ab";
+
+ PARCBuffer *address = parcNetwork_ParseLinkAddress("link://01:23:45:67:89:ab");
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcNetwork_LinkAddress_BuildString((unsigned char *) parcBuffer_Overlay(address, 0), parcBuffer_Remaining(address), composer);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *actual = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcBufferComposer_Release(&composer);
+ parcBuffer_Release(&address);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_dashes)
+{
+ char *expected = "link://01-23-45-67-89-ab";
+ PARCBuffer *address = parcNetwork_ParseLinkAddress(expected);
+ parcBuffer_Flip(address);
+
+ PARCBuffer *e = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ parcBuffer_SetPosition(address, 0);
+ parcBuffer_SetLimit(address, 6);
+
+ parcBuffer_SetPosition(e, 0);
+ parcBuffer_SetLimit(e, 6);
+
+ assertTrue(parcBuffer_Equals(address, e),
+ "Expected result failed.");
+
+ parcBuffer_Release(&e);
+ parcBuffer_Release(&address);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_colons)
+{
+ char *expected = "link://01:23:45:67:89:ab";
+ PARCBuffer *address = parcNetwork_ParseLinkAddress(expected);
+
+ PARCBuffer *e = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ parcBuffer_SetPosition(address, 0);
+ parcBuffer_SetPosition(e, 0);
+ parcBuffer_SetLimit(address, 6);
+ parcBuffer_SetLimit(e, 6);
+
+ assertTrue(parcBuffer_Equals(address, e),
+ "Expected result failed.");
+
+ parcBuffer_Release(&e);
+ parcBuffer_Release(&address);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_LinkAddress_Parse_dots)
+{
+ char *expected = "link://0123.4567.89ab";
+ PARCBuffer *address = parcNetwork_ParseLinkAddress(expected);
+
+ PARCBuffer *e = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ parcBuffer_SetPosition(address, 0);
+ parcBuffer_SetPosition(e, 0);
+ parcBuffer_SetLimit(address, 6);
+ parcBuffer_SetLimit(e, 6);
+
+ assertTrue(parcBuffer_Equals(address, e),
+ "Expected result failed.");
+
+ parcBuffer_Release(&e);
+ parcBuffer_Release(&address);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcNetwork_ParseLinkAddress_BadScheme, .event = &LongBowTrapIllegalValue)
+{
+ char *expected = "asdf://";
+ parcNetwork_ParseLinkAddress(expected);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcNetwork_LinkAddress_Parse_BadLink, .event = &LongBowTrapIllegalValue)
+{
+ char *expected = "link://";
+ parcNetwork_ParseLinkAddress(expected);
+ printf("Hello\n");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcNetwork_LinkAddress_Parse_BadSpecification, .event = &LongBowTrapIllegalValue)
+{
+ char *expected = "link://a";
+ parcNetwork_ParseLinkAddress(expected);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcNetwork_LinkAddress_Parse_BadMixOfDashesAndDots, .event = &LongBowTrapIllegalValue)
+{
+ char *expected = "link://01-23-45.6789ab";
+ parcNetwork_ParseLinkAddress(expected);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcNetwork_LinkAddress_Parse_BadMixOfDotsAndDashes, .event = &LongBowTrapIllegalValue)
+{
+ char *expected = "link://012345.67-89-ab";
+ parcNetwork_ParseLinkAddress(expected);
+}
+
+LONGBOW_TEST_CASE(Global, parseMAC48Address)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ bool actual = parcNetwork_ParseMAC48Address("01-23-45-67-89-ab", buffer);
+ assertTrue(actual, "Expected parcNetwork_ParseMAC48Address() to return true");
+
+ parcBuffer_Flip(buffer);
+
+ assertTrue(parcBuffer_Equals(expected, buffer), "Expected buffer contents failed.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ bool actual = parcNetwork_ParseMAC48Address("01:23:45:67:89:ab", buffer);
+ assertTrue(actual, "Expected parcNetwork_ParseMAC48Address() to return true");
+ parcBuffer_Flip(buffer);
+
+ assertTrue(parcBuffer_Equals(expected, buffer), "Expected buffer contents failed.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons_TooShort)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ bool actual = parcNetwork_ParseMAC48Address("01:23:45:67:89", buffer);
+ assertFalse(actual, "Expected parcNetwork_ParseMAC48Address() to return false");
+ assertTrue(parcBuffer_Position(buffer) == 0, "Expected buffer to be unmodified.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_ParseMAC48Address_Colons_Garbage)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ bool actual = parcNetwork_ParseMAC48Address("0x:23:45:67:89:ab", buffer);
+ assertFalse(actual, "Expected parcNetwork_ParseMAC48Address() to return false");
+ assertTrue(parcBuffer_Position(buffer) == 0, "Expected the PARCBuffer to be unchanged.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_ParseMAC48Address)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ bool actual = parcNetwork_ParseMAC48Address("0123.4567.89ab", buffer);
+ assertTrue(actual, "Expected _parseLinkAddressDot() to return true");
+ parcBuffer_Flip(buffer);
+
+ assertTrue(parcBuffer_Equals(expected, buffer), "Expected buffer contents failed.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_ParseMAC48Address_TooShort)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ bool actual = parcNetwork_ParseMAC48Address("0123.4567", buffer);
+ assertFalse(actual, "Expected parcNetwork_ParseMAC48Address() to return false");
+ assertTrue(parcBuffer_Position(buffer) == 0, "Expected the PARCBuffer to be unchanged.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_ParseInet4Address)
+{
+ struct sockaddr_in *address = parcNetwork_SockInet4Address("127.0.0.1", 1234);
+
+ PARCBufferComposer *composer = parcNetwork_SockInet4Address_BuildString(address, parcBufferComposer_Create());
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *addressURI = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ struct sockaddr_in *actual = parcNetwork_ParseInet4Address(addressURI);
+
+ assertTrue(parcNetwork_Inet4Equals(address, actual),
+ "Expected Addresses are not equal");
+
+ parcMemory_Deallocate((void **) &actual);
+ parcMemory_Deallocate((void **) &addressURI);
+ parcBufferComposer_Release(&composer);
+ parcMemory_Deallocate((void **) &address);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_Inet4Equals)
+{
+ struct sockaddr_in *x = parcNetwork_SockInet4Address("127.0.0.1", 1234);
+ struct sockaddr_in *y = parcNetwork_SockInet4Address("127.0.0.1", 1234);
+ struct sockaddr_in *z = parcNetwork_SockInet4Address("127.0.0.1", 1234);
+ struct sockaddr_in *u1 = parcNetwork_SockInet4Address("127.0.0.2", 1234);
+ struct sockaddr_in *u2 = parcNetwork_SockInet4Address("127.0.0.1", 4567);
+
+ parcObjectTesting_AssertEqualsFunction(parcNetwork_Inet4Equals, x, y, z, u1, u2);
+
+ parcMemory_Deallocate((void **) &x);
+ parcMemory_Deallocate((void **) &y);
+ parcMemory_Deallocate((void **) &z);
+ parcMemory_Deallocate((void **) &u1);
+ parcMemory_Deallocate((void **) &u2);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_SockAddress_ipv4)
+{
+ const char *ipv4 = "1.1.1.1";
+ unsigned short port = 5959;
+
+ struct sockaddr_in truth = {
+ .sin_family = PF_INET,
+ .sin_port = htons(port),
+ .sin_addr.s_addr = htonl(0x01010101)
+ };
+
+ struct sockaddr_in *test = (struct sockaddr_in *) parcNetwork_SockAddress(ipv4, port);
+ assertNotNull(test, "Got null address for %s port %u", ipv4, port);
+ assertTrue(truth.sin_family == test->sin_family, "wrong family, expected %d got %d", truth.sin_family, test->sin_family);
+ assertTrue(truth.sin_port == test->sin_port, "wrong port, expected %u got %u", truth.sin_port, test->sin_port);
+
+ assertTrue(memcmp(&truth.sin_addr, &test->sin_addr, sizeof(struct in_addr)) == 0, "struct in_addr did not compare");
+ parcMemory_Deallocate((void **) &test);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_SockAddress_ipv6)
+{
+ const char *ipv6 = "fe80::aa20:66ff:fe00:314a";
+ uint8_t truth_addr[16] = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0xaa, 0x20, 0x66, 0xff, 0xfe, 0x00, 0x31, 0x4a };
+
+ unsigned short port = 5959;
+
+ struct sockaddr_in6 truth = {
+ .sin6_family = PF_INET6,
+ .sin6_port = htons(port)
+ };
+
+ memcpy(&truth.sin6_addr, truth_addr, sizeof(truth.sin6_addr));
+
+
+ struct sockaddr_in6 *test = (struct sockaddr_in6 *) parcNetwork_SockAddress(ipv6, port);
+ if (test == NULL) {
+ testSkip("IPv6 is not supported in the runtime environment.");
+ }
+ assertTrue(truth.sin6_family == test->sin6_family, "wrong family, expected %d got %d", truth.sin6_family, test->sin6_family);
+ assertTrue(truth.sin6_port == test->sin6_port, "wrong port, expected %u got %u", truth.sin6_port, test->sin6_port);
+
+ assertTrue(memcmp(&truth.sin6_addr, &test->sin6_addr, sizeof(struct in6_addr)) == 0, "struct in_addr did not compare");
+ parcMemory_Deallocate((void **) &test);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_SockAddress_hostname)
+{
+ const char *name = "localhost";
+ unsigned short port = 5959;
+
+ struct sockaddr *test = parcNetwork_SockAddress(name, port);
+ assertNotNull(test, "Got null looking up '%s'", name);
+ parcMemory_Deallocate((void **) &test);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_LOCAL)
+{
+ struct sockaddr_un name;
+ name.sun_family = PF_LOCAL;
+
+ bool isLocal = parcNetwork_IsSocketLocal((struct sockaddr *) &name);
+ assertTrue(isLocal, "PF_LOCAL address did not return as local");
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_IPX)
+{
+ struct sockaddr_un name;
+ name.sun_family = PF_IPX;
+
+ bool isLocal = parcNetwork_IsSocketLocal((struct sockaddr *) &name);
+ assertFalse(isLocal, "Expected parcNetwork_IsSocketLocal(PF_PUP) to return false");
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_INET4)
+{
+ struct sockaddr *s = parcNetwork_SockAddress("127.1.1.1", 5900);
+ bool isLoopback = parcNetwork_IsSocketLocal(s);
+ assertTrue(isLoopback, "127.1.1.1 should be called loopback");
+ parcMemory_Deallocate((void **) &s);
+}
+
+LONGBOW_TEST_CASE(Global, parcNetwork_IsSocketLocal_PF_INET6)
+{
+ struct sockaddr *s = parcNetwork_SockAddress("::1", 5900);
+ bool isLoopback = parcNetwork_IsSocketLocal(s);
+ assertTrue(isLoopback, "::1 should be called loopback");
+ parcMemory_Deallocate((void **) &s);
+}
+
+
+// =======================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, parcNetwork_IsInet6Local_True);
+ LONGBOW_RUN_TEST_CASE(Local, parcNetwork_IsInet6Local_False);
+ LONGBOW_RUN_TEST_CASE(Local, parcNetwork_IsInet4Local_True);
+ LONGBOW_RUN_TEST_CASE(Local, parcNetwork_IsInet4Local_False);
+
+ LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDashOrColon);
+ LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons);
+ LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDot);
+ LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDot_TooShort);
+ LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons_TooShort);
+ LONGBOW_RUN_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons_Garbage);
+}
+
+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, parcNetwork_IsInet6Local_True)
+{
+ struct sockaddr *s = parcNetwork_SockAddress("::1", 5900);
+
+ bool isLoopback = _isInet6Loopback((struct sockaddr_in6 *) s);
+ assertTrue(isLoopback, "::1 should be called loopback");
+ parcMemory_Deallocate((void **) &s);
+}
+
+LONGBOW_TEST_CASE(Local, parcNetwork_IsInet6Local_False)
+{
+ struct sockaddr *s = parcNetwork_SockAddress("fe80::aa20:66ff:fe00:1", 5900);
+
+ bool isLoopback = _isInet6Loopback((struct sockaddr_in6 *) s);
+ assertFalse(isLoopback, "fe80::aa20:66ff:fe00:1 should not be called loopback");
+ parcMemory_Deallocate((void **) &s);
+}
+
+LONGBOW_TEST_CASE(Local, parcNetwork_IsInet4Local_True)
+{
+ struct sockaddr *s = parcNetwork_SockAddress("127.1.1.1", 5900);
+
+ bool isLoopback = _isInet4Loopback((struct sockaddr_in *) s);
+ assertTrue(isLoopback, "127.1.1.1 should be called loopback");
+ parcMemory_Deallocate((void **) &s);
+}
+
+LONGBOW_TEST_CASE(Local, parcNetwork_IsInet4Local_False)
+{
+ struct sockaddr *s = parcNetwork_SockAddress("13.1.1.1", 5900);
+
+ bool isLoopback = _isInet4Loopback((struct sockaddr_in *) s);
+ assertFalse(isLoopback, "13.1.1.1 should not be called loopback");
+ parcMemory_Deallocate((void **) &s);
+}
+
+LONGBOW_TEST_CASE(Local, _parseMAC48AddressDashOrColon)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ PARCBuffer *actual = _parseMAC48AddressDashOrColon("01-23-45-67-89-ab", buffer);
+ assertNotNull(actual, "Expected _parseLinkAddressDashOrColon() to return non-NULL value");
+ parcBuffer_Flip(actual);
+
+ assertTrue(parcBuffer_Equals(expected, actual), "Expected buffer contents failed.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ PARCBuffer *actual = _parseMAC48AddressDashOrColon("01:23:45:67:89:ab", buffer);
+ assertNotNull(actual, "Expected _parseLinkAddressDashOrColon() to return non-NULL value");
+ parcBuffer_Flip(actual);
+
+ assertTrue(parcBuffer_Equals(expected, actual), "Expected buffer contents failed.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons_TooShort)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ PARCBuffer *actual = _parseMAC48AddressDashOrColon("01:23:45:67:89", buffer);
+ assertNull(actual, "Expected _parseLinkAddressDashOrColon() to return NULL value");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Local, _parseMAC48AddressDashOrColon_Colons_Garbage)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ PARCBuffer *actual = _parseMAC48AddressDashOrColon("0x:23:45:67:89:ab", buffer);
+ assertNull(actual, "Expected _parseLinkAddressDashOrColon() to return NULL value");
+ assertTrue(parcBuffer_Position(buffer) == 0, "Expected the PARCBuffer to be unchanged.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Local, _parseMAC48AddressDot)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ PARCBuffer *actual = _parseMAC48AddressDot("0123.4567.89ab", buffer);
+ assertNotNull(actual, "Expected _parseLinkAddressDot() to return non-NULL value");
+ parcBuffer_Flip(actual);
+
+ assertTrue(parcBuffer_Equals(expected, actual), "Expected buffer contents failed.");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Local, _parseMAC48AddressDot_TooShort)
+{
+ PARCBuffer *expected = parcBuffer_Wrap((uint8_t []) { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab }, 6, 0, 6);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(7);
+ PARCBuffer *actual = _parseMAC48AddressDot("0123.4567", buffer);
+ assertNull(actual, "Expected _parseLinkAddressDot() to return NULL value");
+
+ parcBuffer_Release(&expected);
+ parcBuffer_Release(&buffer);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Networking);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Object.c b/libparc/parc/algol/test/test_parc_Object.c
new file mode 100755
index 00000000..687654fe
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Object.c
@@ -0,0 +1,1580 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_Object.c"
+
+#include <inttypes.h>
+#include <sys/time.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/testing/parc_MemoryTesting.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_StdlibMemory.h>
+
+typedef struct {
+ int calledCount;
+ int val;
+} _dummy_object;
+
+typedef _dummy_object _DummyObject;
+
+static void
+_dummy_Destroy(_DummyObject **obj __attribute__((unused)))
+{
+}
+
+static _DummyObject *
+_dummy_Copy(const _DummyObject *obj);
+
+
+static bool
+_dummy_Equals(const _DummyObject *x, const _DummyObject *y)
+{
+ const _DummyObject *dummy1 = x;
+ const _DummyObject *dummy2 = y;
+ return (dummy1->calledCount == dummy2->calledCount);
+}
+
+static int
+_dummy_Compare(const _DummyObject *x, const _DummyObject *y)
+{
+ const _DummyObject *dummy1 = x;
+ const _DummyObject *dummy2 = y;
+ if (dummy1->calledCount == dummy2->calledCount) {
+ return 0;
+ } else if (dummy1->calledCount < dummy2->calledCount) {
+ return -1;
+ } else {
+ return 1;
+ }
+}
+
+static uint32_t
+_dummy_HashCode(const _DummyObject *obj)
+{
+ _DummyObject *dummy = (_DummyObject *) obj;
+ dummy->calledCount++;
+ return 1337;
+}
+
+static char *
+_dummy_ToString(const _DummyObject *x __attribute__((unused)))
+{
+ char *str = (char *) parcMemory_Allocate(6);
+ char *test = "dummy";
+ sprintf(str, "%s", test);
+ return str;
+}
+
+static PARCJSON *
+_dummy_ToJSON(const _DummyObject *x __attribute__((unused)))
+{
+ PARCJSON *json = parcJSON_ParseString("{ \"type\" : \"dummy\" }");
+ return json;
+}
+
+parcObject_Override(_DummyObject, PARCObject,
+ .destroy = (PARCObjectDestroy *) _dummy_Destroy,
+ .copy = (PARCObjectCopy *) _dummy_Copy,
+ .toString = (PARCObjectToString *) _dummy_ToString,
+ .equals = (PARCObjectEquals *) _dummy_Equals,
+ .compare = (PARCObjectCompare *) _dummy_Compare,
+ .hashCode = (PARCObjectHashCode *) _dummy_HashCode,
+ .toJSON = (PARCObjectToJSON *) _dummy_ToJSON);
+
+static _DummyObject *
+_dummy_Copy(const _DummyObject *obj)
+{
+ _DummyObject *newDummy = parcObject_CreateInstance(_DummyObject);
+ const _DummyObject *dummy = obj;
+ newDummy->calledCount = dummy->calledCount;
+ return newDummy;
+}
+
+typedef _dummy_object _DummyObjectNoHash;
+parcObject_ExtendPARCObject(_DummyObjectNoHash,
+ _dummy_Destroy,
+ _dummy_Copy,
+ _dummy_ToString,
+ _dummy_Equals,
+ _dummy_Compare,
+ NULL,
+ _dummy_ToJSON);
+
+static bool
+_meta_destructor_true(PARCObject **objPtr)
+{
+ return true;
+}
+
+static bool
+_meta_destructor_false(PARCObject **objPtr)
+{
+ (*objPtr) = NULL;
+ return false;
+}
+
+static PARCObject *
+_meta_copy(const PARCObject *ptr)
+{
+ _DummyObject *d = parcMemory_AllocateAndClear(sizeof(_DummyObject));
+ _DummyObject *xx = (_DummyObject *) ptr;
+ d->val = xx->val;
+ return d;
+}
+
+static bool
+_meta_equals(const PARCObject *x, const PARCObject *y)
+{
+ _DummyObject *xx = (_DummyObject *) x;
+ _DummyObject *yy = (_DummyObject *) y;
+ return (xx->val == yy->val);
+}
+
+static int
+_meta_compare(const PARCObject *x, const PARCObject *y)
+{
+ _DummyObject *xx = (_DummyObject *) x;
+ _DummyObject *yy = (_DummyObject *) y;
+
+ if (xx->val == yy->val) {
+ return 0;
+ } else if (xx->val < yy->val) {
+ return -1;
+ } else {
+ return 1;
+ }
+}
+
+static PARCHashCode
+_meta_hashCode(const PARCObject *ptr)
+{
+ _DummyObject *xx = (_DummyObject *) ptr;
+ return xx->val;
+}
+
+static char *
+_meta_toString(const PARCObject *ptr)
+{
+ _DummyObject *xx = (_DummyObject *) ptr;
+
+ char *result;
+ parcMemory_MemAlign((void **) &result, sizeof(void *), sizeof(char));
+ assertNotNull(result, "parcMemory_Allocate returned NULL");
+
+ char *p = result;
+ sprintf(result, "%d", xx->val);
+
+ return p;
+}
+
+static PARCJSON *
+_meta_toJson(const PARCObject *ptr)
+{
+ _DummyObject *xx = (_DummyObject *) ptr;
+
+ PARCJSON *json = parcJSON_Create();
+ parcJSON_AddInteger(json, "value", xx->val);
+
+ return json;
+}
+
+static const PARCMemoryInterface *_originalMemoryProvider;
+
+LONGBOW_TEST_RUNNER(parcObject)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+ LONGBOW_RUN_TEST_FIXTURE(PARCObjectDescriptor);
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(StaticObjects);
+ LONGBOW_RUN_TEST_FIXTURE(Meta);
+ LONGBOW_RUN_TEST_FIXTURE(AcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Subclasses);
+ LONGBOW_RUN_TEST_FIXTURE(Fail);
+ LONGBOW_RUN_TEST_FIXTURE(Locking);
+ LONGBOW_RUN_TEST_FIXTURE(WaitNotify);
+ LONGBOW_RUN_TEST_FIXTURE(Synchronization);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parcObject)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(parcObject)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, _objectHeaderIsValid);
+ LONGBOW_RUN_TEST_CASE(Static, _parcObject_PrefixLength);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ parcMemory_SetInterface(_originalMemoryProvider);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+struct timeval _testObject;
+
+parcObject_Override(_testObject, PARCObject);
+
+LONGBOW_TEST_CASE(Static, _objectHeaderIsValid)
+{
+ PARCObject *object = parcObject_CreateInstanceImpl(&_testObject_Descriptor);
+
+ _PARCObjectHeader *header = _parcObject_Header(object);
+
+ assertTrue(_parcObjectHeader_IsValid(header, object), "Expected _parcObject_HeaderHeaderIsValid to be valid");
+
+ parcObject_Release(&object);
+}
+
+LONGBOW_TEST_CASE(Static, _parcObject_PrefixLength)
+{
+ // Test that the result is a multiple of the alignment value and greater than the size of _PARCObjectHeader.
+
+ // Compute the power of 2 value of sizeof(void *)
+ unsigned int v = sizeof(void *);
+ unsigned int r = 0; // r will be lg(v)
+
+ while (v >>= 1) {
+ r++;
+ }
+ PARCObjectDescriptor descriptor;
+
+ for (int i = r; i < 20; i++) {
+ descriptor.objectAlignment = 1 << i;
+ size_t actual = _parcObject_PrefixLength(&descriptor);
+ assertTrue((actual & (descriptor.objectAlignment - 1)) == 0,
+ "Alignment needs to be a multiple of %u", descriptor.objectAlignment);
+ }
+}
+
+LONGBOW_TEST_FIXTURE(AcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcObject_Acquire);
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcObject_Release);
+// LONGBOW_RUN_TEST_CASE(AcquireRelease, parcObject_Acquire_Invalid);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease)
+{
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ parcMemory_SetInterface(_originalMemoryProvider);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcObject_Acquire)
+{
+ struct timeval *expected = parcObject_CreateInstanceImpl(&_testObject_Descriptor);
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcObject_Acquire, expected);
+ parcObject_Release((void **) &expected);
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcObject_Release)
+{
+ struct timeval *time = parcObject_CreateInstanceImpl(&_testObject_Descriptor);
+ parcObject_AssertValid(time);
+
+ time->tv_sec = 1;
+ time->tv_usec = 2;
+
+ PARCReferenceCount count = parcObject_Release((PARCObject **) &time);
+ assertTrue(count == 0, "Expected reference count to be zero");
+ assertTrue(time == 0, "Expected memory pointer to be NULL after destroy.");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Create);
+// LONGBOW_RUN_TEST_CASE(Global, parcObject_CreateAndClear);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_IsValid);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_IsValid_NotValid);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_IsInstanceOf);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Copy_Default);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Compare_Default);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Compare_NoOverride);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Equals_Default);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Equals_NoOverride);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_HashCode_Default);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_HashCode_NoOverride);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_ToString_Default);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_ToString_NoOverride);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_ToJSON_Default);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_ToJSON_NoOverride);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_GetReferenceCount);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Display_Default);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Display_NoOverride);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcObject_GetDescriptor);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+
+ parcMemory_SetInterface(_originalMemoryProvider);
+
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Release)
+{
+ struct timeval *time = parcObject_CreateInstanceImpl(&_testObject_Descriptor);
+ parcObject_AssertValid(time);
+
+ time->tv_sec = 1;
+ time->tv_usec = 2;
+
+ PARCReferenceCount count = parcObject_Release((PARCObject **) &time);
+ assertTrue(count == 0, "Expected reference count to be zero");
+ assertTrue(time == 0, "Expected memory pointer to be NULL after destroy.");
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Create)
+{
+ struct timeval *time = parcObject_CreateInstanceImpl(&_testObject_Descriptor);
+ parcObject_AssertValid(time);
+
+ time->tv_sec = 1;
+ time->tv_usec = 2;
+
+ PARCReferenceCount count = parcObject_Release((PARCObject **) &time);
+ assertTrue(count == 0, "Expected reference count to be zero");
+ assertTrue(time == 0, "Expected memory pointer to be NULL after destroy.");
+}
+
+//LONGBOW_TEST_CASE(Global, parcObject_CreateAndClear)
+//{
+// struct timeval *time = parcObject_CreateAndClear(struct timeval);
+// parcObject_AssertValid(time);
+//
+// time->tv_sec = 1;
+// time->tv_usec = 2;
+//
+// PARCReferenceCount count = parcObject_Release((PARCObject **) &time);
+// assertTrue(count == 0, "Expected reference count to be zero");
+// assertTrue(time == 0, "Expected memory pointer to be NULL after destroy.");
+//}
+
+LONGBOW_TEST_CASE(Global, parcObject_IsValid)
+{
+ PARCObject *object = parcObject_CreateInstanceImpl(&_testObject_Descriptor);
+ assertTrue(parcObject_IsValid(object), "Expected valid PARCObject");
+
+ parcObject_Release(&object);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_IsInstanceOf)
+{
+ _DummyObject *dummy1 = parcObject_CreateInstance(_DummyObject);
+ assertTrue(parcObject_IsInstanceOf(dummy1, &PARCObject_Descriptor),
+ "Expected _DummyObject to be an instance of PARCObject");
+
+ parcObject_Release((PARCObject **) &dummy1);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_IsValid_NotValid)
+{
+ PARCObject *object = parcObject_CreateInstanceImpl(&_testObject_Descriptor);
+ PARCObject *alias = object;
+ parcObject_Release(&object);
+ assertFalse(parcObject_IsValid(object), "Expected invalid PARCObject");
+ assertFalse(parcObject_IsValid(alias), "Expected invalid PARCObject");
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Copy_Default)
+{
+ struct timeval *time = parcObject_CreateInstanceImpl(&_testObject_Descriptor);
+ parcObject_AssertValid(time);
+
+ time->tv_sec = 1;
+ time->tv_usec = 2;
+
+ struct timeval *copy = parcObject_Copy(time);
+
+ parcObject_AssertValid(copy);
+
+ assertTrue(copy->tv_sec == 1, "Expected tv_sec to equal 1");
+ assertTrue(copy->tv_usec == 2, "Expected tv_usec to equal 2");
+
+ PARCReferenceCount count = parcObject_Release((PARCObject **) &copy);
+ assertTrue(count == 0, "Expected reference count to be zero");
+ assertTrue(copy == 0, "Expected memory pointer to be NULL after destroy.");
+
+ parcObject_Release((PARCObject *) &time);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Copy)
+{
+ _DummyObject *dummy1 = parcObject_CreateInstance(_DummyObject);
+ dummy1->calledCount = 100;
+
+ _DummyObject *dummy2 = parcObject_Copy(dummy1);
+
+ assertTrue(dummy2->calledCount == dummy1->calledCount,
+ "Expected called counts to be the same. Got %d, expected %d.", dummy1->calledCount, dummy2->calledCount);
+
+ parcObject_Release((PARCObject **) &dummy1);
+ parcObject_Release((PARCObject **) &dummy2);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Compare_Default)
+{
+ struct timeval *time1 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+ parcObject_AssertValid(time1);
+
+ time1->tv_sec = 1;
+ time1->tv_usec = 2;
+
+ struct timeval *time2 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+ parcObject_AssertValid(time2);
+
+ time2->tv_sec = 1;
+ time2->tv_usec = 2;
+
+ int compareResult = parcObject_Compare(time1, time2);
+ assertTrue(compareResult == 0, "Expected objects to compare equal. Comparison result: %d", compareResult);
+ compareResult = parcObject_Compare(time1, time1);
+ assertTrue(compareResult == 0, "Expected same object to be equal since they have identical pointer addresses. Comparison result: %d", compareResult);
+
+ parcObject_Release((PARCObject *) &time1);
+ parcObject_Release((PARCObject *) &time2);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Compare_NoOverride)
+{
+ const PARCObjectDescriptor *descriptor =
+ parcObjectDescriptor_Create("override",
+ sizeof(struct timeval), sizeof(void*),
+ true,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL);
+ struct timeval *time1 = parcObject_CreateAndClearInstanceImpl(descriptor);
+ parcObject_AssertValid(time1);
+
+ time1->tv_sec = 1;
+ time1->tv_usec = 2;
+
+ struct timeval *time2 = parcObject_CreateAndClearInstanceImpl(descriptor);
+ parcObject_AssertValid(time2);
+
+ time2->tv_sec = 1;
+ time2->tv_usec = 2;
+
+ int compareResult = parcObject_Compare(time1, time2);
+ assertTrue(compareResult == 0, "Expected objects to compare equal. Comparison result: %d", compareResult);
+ compareResult = parcObject_Compare(time1, time1);
+ assertTrue(compareResult == 0, "Expected same object to be equal since they have identical pointer addresses. Comparison result: %d", compareResult);
+
+ parcObject_Release((PARCObject *) &time1);
+ parcObject_Release((PARCObject *) &time2);
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Compare)
+{
+ _DummyObject *value = parcObject_CreateAndClearInstance(_DummyObject);
+ _DummyObject *equality[2];
+ equality[0] = parcObject_CreateAndClearInstance(_DummyObject);
+ equality[1] = NULL;
+ _DummyObject *lesser[2];
+ lesser[0] = parcObject_CreateAndClearInstance(_DummyObject);
+ lesser[1] = NULL;
+
+ _DummyObject *greater[2];
+ greater[0] = parcObject_CreateAndClearInstance(_DummyObject);
+ greater[1] = NULL;
+
+ value->calledCount = 50;
+ equality[0]->calledCount = 50;
+ lesser[0]->calledCount = 10;
+ greater[0]->calledCount = 80;
+
+ parcObjectTesting_AssertCompareTo(parcObject_Compare, value, equality, lesser, greater);
+
+ parcObject_Release((void **) &value);
+ parcObject_Release((void **) &equality[0]);
+ parcObject_Release((void **) &lesser[0]);
+ parcObject_Release((void **) &greater[0]);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Equals_Default)
+{
+ struct timeval *x = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+ memset(x, 0, sizeof(struct timeval));
+ x->tv_sec = 1;
+ x->tv_usec = 2;
+
+ struct timeval *y = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+ memset(y, 0, sizeof(struct timeval));
+ y->tv_sec = 1;
+ y->tv_usec = 2;
+
+ assertTrue(parcObject_Equals(x, y), "Expected equality");
+
+ struct timeval *z = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+ z->tv_sec = 1;
+ z->tv_usec = 2;
+
+ struct timeval *unequal1 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+ unequal1->tv_sec = 1;
+ unequal1->tv_usec = 1;
+
+ struct timeval *unequal2 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+ unequal2->tv_sec = 0;
+ unequal2->tv_usec = 0;
+
+ parcObjectTesting_AssertEqualsFunction(parcObject_Equals, x, y, z, unequal1, unequal2, NULL);
+
+ parcObject_Release((PARCObject *) &x);
+ parcObject_Release((PARCObject *) &y);
+ parcObject_Release((PARCObject *) &z);
+ parcObject_Release((PARCObject *) &unequal1);
+ parcObject_Release((PARCObject *) &unequal2);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Equals_NoOverride)
+{
+ const PARCObjectDescriptor *descriptor =
+ parcObjectDescriptor_Create("override", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL);
+
+ struct timeval *x = parcObject_CreateAndClearInstanceImpl(descriptor);
+ memset(x, 0, sizeof(struct timeval));
+ x->tv_sec = 1;
+ x->tv_usec = 2;
+
+ struct timeval *y = parcObject_CreateAndClearInstanceImpl(descriptor);
+ memset(y, 0, sizeof(struct timeval));
+ y->tv_sec = 1;
+ y->tv_usec = 2;
+
+ assertTrue(parcObject_Equals(x, y), "Expected equality");
+
+ struct timeval *z = parcObject_CreateAndClearInstanceImpl(descriptor);
+ z->tv_sec = 1;
+ z->tv_usec = 2;
+
+ struct timeval *unequal1 = parcObject_CreateAndClearInstanceImpl(descriptor);
+ unequal1->tv_sec = 1;
+ unequal1->tv_usec = 1;
+
+ struct timeval *unequal2 = parcObject_CreateAndClearInstanceImpl(descriptor);
+ unequal2->tv_sec = 0;
+ unequal2->tv_usec = 0;
+
+ parcObjectTesting_AssertEqualsFunction(parcObject_Equals, x, y, z, unequal1, unequal2, NULL);
+
+ parcObject_Release((PARCObject *) &x);
+ parcObject_Release((PARCObject *) &y);
+ parcObject_Release((PARCObject *) &z);
+ parcObject_Release((PARCObject *) &unequal1);
+ parcObject_Release((PARCObject *) &unequal2);
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Equals)
+{
+ _DummyObject *x = parcObject_CreateInstance(_DummyObject);
+ x->calledCount = 100;
+ _DummyObject *y = parcObject_CreateInstance(_DummyObject);
+ y->calledCount = 100;
+ _DummyObject *z = parcObject_CreateInstance(_DummyObject);
+ z->calledCount = 100;
+
+ _DummyObject *unequal1 = parcObject_CreateInstance(_DummyObject);
+ unequal1->calledCount = 50;
+
+ PARCObject *unequal2 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+
+ PARCObjectDescriptor dummyMeta2 = parcObject_DescriptorName(_DummyObject);
+ _DummyObject *unequal3 = parcObject_CreateAndClearInstanceImpl(&dummyMeta2);
+ unequal3->calledCount = 100;
+
+ PARCObject *unequal4 = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+
+ parcObjectTesting_AssertEqualsFunction(parcObject_Equals, x, y, z, unequal1, unequal2, unequal3, unequal4, NULL);
+
+ parcObject_Release((PARCObject **) &x);
+ parcObject_Release((PARCObject **) &y);
+ parcObject_Release((PARCObject **) &z);
+ parcObject_Release((PARCObject **) &unequal1);
+ parcObject_Release((PARCObject **) &unequal2);
+ parcObject_Release((PARCObject **) &unequal3);
+ parcObject_Release((PARCObject **) &unequal4);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_HashCode_Default)
+{
+ struct timeval *time = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+ parcObject_AssertValid(time);
+
+ time->tv_sec = 1;
+ time->tv_usec = 2;
+
+ PARCHashCode hashCode = parcObject_HashCode(time);
+ PARCHashCode expected = parcHashCode_Hash((void *) time, sizeof(struct timeval));
+ assertTrue(hashCode == expected, "Hash codes do not match. Got %" PRIPARCHashCode ", expected %" PRIPARCHashCode ".", hashCode, expected);
+
+ parcObject_Release((PARCObject *) &time);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_HashCode_NoOverride)
+{
+ const PARCObjectDescriptor *descriptor =
+ parcObjectDescriptor_Create("override", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL);
+ struct timeval *time = parcObject_CreateAndClearInstanceImpl(descriptor);
+ parcObject_AssertValid(time);
+
+ time->tv_sec = 1;
+ time->tv_usec = 2;
+
+ PARCHashCode hashCode = parcObject_HashCode(time);
+ PARCHashCode expected = parcHashCode_Hash((void *) time, sizeof(struct timeval));
+ assertTrue(hashCode == expected, "Hash codes do not match. Got %" PRIPARCHashCode ", expected %" PRIPARCHashCode ".", hashCode, expected);
+
+ parcObject_Release((PARCObject *) &time);
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_HashCode)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ PARCHashCode hashCode = parcObject_HashCode(dummy);
+ assertTrue(hashCode == 1337, "Expected hashcode to be 1337, got %" PRIPARCHashCode, hashCode);
+
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_ToString)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ char *strRep = parcObject_ToString(dummy);
+ assertTrue(strcmp(strRep, "dummy") == 0, "Expected 'dummy' string representation, got %s", strRep);
+
+ parcMemory_Deallocate((void **) &strRep);
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_ToString_Default)
+{
+ _DummyObject *dummy = parcObject_CreateAndClearInstanceImpl(&_DummyObject_Descriptor);
+
+ char *strRep = parcObject_ToString(dummy);
+
+ parcMemory_Deallocate((void **) &strRep);
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_ToString_NoOverride)
+{
+ const PARCObjectDescriptor *descriptor =
+ parcObjectDescriptor_Create("override", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL);
+ _DummyObject *dummy = parcObject_CreateAndClearInstanceImpl(descriptor);
+
+ char *strRep = parcObject_ToString(dummy);
+
+ parcMemory_Deallocate((void **) &strRep);
+ parcObject_Release((PARCObject **) &dummy);
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_ToJSON_Default)
+{
+ size_t expectedSize = sizeof(struct timeval);
+ PARCObject *memory = parcObject_CreateAndClearInstanceImpl(&_testObject_Descriptor);
+
+ PARCJSON *json = parcObject_ToJSON(memory);
+
+ const PARCJSONPair *lengthPair = parcJSON_GetPairByName(json, "objectLength");
+ PARCJSONValue *lengthValue = parcJSONPair_GetValue(lengthPair);
+ uint64_t actualLength = parcJSONValue_GetInteger(lengthValue);
+
+ const PARCJSONPair *alignmentPair = parcJSON_GetPairByName(json, "objectAlignment");
+ PARCJSONValue *alignmentValue = parcJSONPair_GetValue(alignmentPair);
+ int alignment = (int) parcJSONValue_GetInteger(alignmentValue);
+
+ assertTrue(actualLength >= expectedSize,
+ "Expected length to be >= %zd, actual %" PRIu64 "", expectedSize, actualLength);
+ assertTrue(alignment == sizeof(void *), "Expected objectAlignment to be %zd, got %d",
+ sizeof(void *), alignment);
+
+ parcJSON_Release(&json);
+ parcObject_Release(&memory);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_ToJSON)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ PARCJSON *json = parcObject_ToJSON(dummy);
+ char *strRep = parcJSON_ToString(json);
+ assertTrue(strcmp(strRep, "{ \"type\" : \"dummy\" }") == 0, "Expected fixed JSON object with a specific string representation, got %s", strRep);
+
+ parcMemory_Deallocate((void **) &strRep);
+ parcJSON_Release(&json);
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_ToJSON_NoOverride)
+{
+ const PARCObjectDescriptor *descriptor =
+ parcObjectDescriptor_Create("override", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL);
+
+ size_t expectedSize = sizeof(struct timeval);
+ PARCObject *memory = parcObject_CreateAndClearInstanceImpl(descriptor);
+
+ PARCJSON *json = parcObject_ToJSON(memory);
+ const PARCJSONPair *lengthPair = parcJSON_GetPairByName(json, "objectLength");
+ PARCJSONValue *lengthValue = parcJSONPair_GetValue(lengthPair);
+ uint64_t actualLength = parcJSONValue_GetInteger(lengthValue);
+
+ const PARCJSONPair *alignmentPair = parcJSON_GetPairByName(json, "objectAlignment");
+ PARCJSONValue *alignmentValue = parcJSONPair_GetValue(alignmentPair);
+ int alignment = (int) parcJSONValue_GetInteger(alignmentValue);
+
+ assertTrue(actualLength >= expectedSize,
+ "Expected length to be >= %zd, actual %" PRIu64 "", expectedSize, actualLength);
+ assertTrue(alignment == sizeof(void *), "Expected objectAlignment to be %zd, got %d",
+ sizeof(void *), alignment);
+
+ parcJSON_Release(&json);
+ parcObject_Release(&memory);
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_GetReferenceCount)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+ PARCReferenceCount refCount = parcObject_GetReferenceCount(dummy);
+ assertTrue(refCount == 1, "Expected reference count to be 1, got %" PRIu64 "", refCount);
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Display_Default)
+{
+ _DummyObject *dummy = parcObject_CreateAndClearInstanceImpl(&_DummyObject_Descriptor);
+ parcObject_Display(dummy, 0);
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Display_NoOverride)
+{
+ const PARCObjectDescriptor *descriptor =
+ parcObjectDescriptor_Create("override", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL);
+
+ _DummyObject *dummy = parcObject_CreateAndClearInstanceImpl(descriptor);
+ parcObject_Display(dummy, 0);
+ parcObject_Release((PARCObject **) &dummy);
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_Display)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+ parcObject_Display(dummy, 0);
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(Global, parcObject_GetDescriptor)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+ const PARCObjectDescriptor *descriptor = parcObject_GetDescriptor(dummy);
+
+ assertTrue(descriptor == &_DummyObject_Descriptor, "Expected pointer to _DummyObject_Descriptor");
+
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_FIXTURE(Subclasses)
+{
+ LONGBOW_RUN_TEST_CASE(Subclasses, parcObject_Copy);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Subclasses)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Subclasses)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ parcMemory_SetInterface(_originalMemoryProvider);
+
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Subclasses, parcObject_Copy)
+{
+ const PARCObjectDescriptor *objectType =
+ parcObjectDescriptor_Create("Dummy", sizeof(_DummyObject), sizeof(void*), true,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &PARCObject_Descriptor, NULL);
+
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+ parcObject_SetDescriptor(dummy, objectType);
+
+ dummy->calledCount = 100;
+
+ _DummyObject *dummy2 = parcObject_Copy(dummy);
+
+ assertTrue(dummy2->calledCount == dummy->calledCount,
+ "Expected called counts to be the same. Got %d, expected %d.", dummy->calledCount, dummy2->calledCount);
+
+ parcObject_Release((PARCObject **) &dummy);
+ parcObject_Release((PARCObject **) &dummy2);
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &objectType);
+}
+
+LONGBOW_TEST_FIXTURE(Locking)
+{
+ LONGBOW_RUN_TEST_CASE(Locking, parcObject_TryLock_Unlock);
+ LONGBOW_RUN_TEST_CASE(Locking, parcObject_Lock_Unlock);
+ LONGBOW_RUN_TEST_CASE(Locking, parcObject_TryLock_AlreadyLockedSameThread);
+ LONGBOW_RUN_TEST_CASE(Locking, parcObject_Lock_AlreadyLocked);
+}
+static uint32_t initialAllocations;
+
+LONGBOW_TEST_FIXTURE_SETUP(Locking)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ initialAllocations = parcMemory_Outstanding();
+
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ longBowTestCase_SetClipBoardData(testCase, dummy);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Locking)
+{
+ _DummyObject *dummy = longBowTestCase_GetClipBoardData(testCase);
+
+ parcObject_Release((PARCObject **) &dummy);
+
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ parcMemory_SetInterface(_originalMemoryProvider);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ parcMemory_SetInterface(_originalMemoryProvider);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Locking, parcObject_TryLock_Unlock)
+{
+ _DummyObject *dummy = longBowTestCase_GetClipBoardData(testCase);
+
+ bool actual = parcObject_TryLock(dummy);
+
+ assertTrue(actual, "Expected parcObject_TryLock to succeed.");
+
+ actual = parcObject_IsLocked(dummy);
+ assertTrue(actual, "Expected parcObject_IsLocked to be true.");
+
+ actual = parcObject_Unlock(dummy);
+ assertTrue(actual, "Expected parcObject_Unlock to succeed.");
+
+ actual = parcObject_IsLocked(dummy);
+ assertFalse(actual, "Expected parcObject_IsLocked to be false.");
+}
+
+LONGBOW_TEST_CASE(Locking, parcObject_Lock_Unlock)
+{
+ _DummyObject *dummy = longBowTestCase_GetClipBoardData(testCase);
+
+ bool actual = parcObject_Lock(dummy);
+
+ assertTrue(actual, "Expected parcObject_Lock to succeed.");
+
+ actual = parcObject_IsLocked(dummy);
+ assertTrue(actual, "Expected parcObject_IsLocked to be true.");
+
+ actual = parcObject_Unlock(dummy);
+ assertTrue(actual, "Expected parcObject_Unlock to succeed.");
+
+ actual = parcObject_IsLocked(dummy);
+ assertFalse(actual, "Expected parcObject_IsLocked to be false.");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Locking, parcObject_TryLock_AlreadyLockedSameThread, .event = &LongBowTrapCannotObtainLockEvent)
+{
+ _DummyObject *dummy = longBowTestCase_GetClipBoardData(testCase);
+
+ bool actual = parcObject_TryLock(dummy);
+
+ assertTrue(actual, "Expected parcObject_TryLock to succeed.");
+
+ actual = parcObject_TryLock(dummy);
+
+ assertFalse(actual, "Expected parcObject_TryLock to fail when already locked by the same thread.");
+
+ actual = parcObject_Unlock(dummy);
+ assertTrue(actual, "Expected parcObject_Unlock to succeed.");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Locking, parcObject_Lock_AlreadyLocked, .event = &LongBowTrapCannotObtainLockEvent)
+{
+ _DummyObject *dummy = longBowTestCase_GetClipBoardData(testCase);
+
+ bool actual = parcObject_Lock(dummy);
+
+ assertTrue(actual, "Expected parcObject_Lock to succeed.");
+
+ actual = parcObject_IsLocked(dummy);
+ assertTrue(actual, "Expected locked object to indicate being locked.");
+
+ parcObject_Lock(dummy);
+}
+
+LONGBOW_TEST_FIXTURE(WaitNotify)
+{
+ LONGBOW_RUN_TEST_CASE(WaitNotify, parcObject_WaitNotify);
+ LONGBOW_RUN_TEST_CASE(WaitNotify, parcObject_WaitNotify2);
+ LONGBOW_RUN_TEST_CASE(WaitNotify, parcObject_WaitUntil);
+ LONGBOW_RUN_TEST_CASE(WaitNotify, parcObject_WaitFor);
+ LONGBOW_RUN_TEST_CASE(WaitNotify, parcObject_WaitNotifyAll);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(WaitNotify)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(WaitNotify)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+
+ parcMemory_SetInterface(_originalMemoryProvider);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// Just wait until told to wakeup, then increment a counter and unlock.
+static void *
+waiter(void *data)
+{
+ _DummyObject *dummy = data;
+
+ while (parcObject_TryLock(dummy) == false) {
+ ;
+ }
+ assertTrue(parcObject_IsLocked(dummy), "%p object %p not locked.", (void *) pthread_self(), (void *) dummy);
+ parcObject_Wait(dummy);
+
+ dummy->val++;
+ parcObject_Unlock(dummy);
+
+ return data;
+}
+
+LONGBOW_TEST_CASE(WaitNotify, parcObject_WaitNotify)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ dummy->val = 0;
+
+ pthread_t thread_A;
+ pthread_t thread_B;
+ pthread_t thread_C;
+ pthread_create(&thread_A, NULL, waiter, dummy);
+ pthread_create(&thread_B, NULL, waiter, dummy);
+ pthread_create(&thread_C, NULL, waiter, dummy);
+
+ while (dummy->val != 3) {
+ while (parcObject_TryLock(dummy) == false) {
+ ;
+ }
+ parcObject_Notify(dummy);
+ parcObject_Unlock(dummy);
+ }
+
+ pthread_join(thread_A, NULL);
+// pthread_join(thread_B, NULL);
+// pthread_join(thread_C, NULL);
+
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(WaitNotify, parcObject_WaitNotifyAll)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ dummy->val = 0;
+
+ pthread_t thread_A;
+ pthread_t thread_B;
+ pthread_t thread_C;
+ pthread_create(&thread_A, NULL, waiter, dummy);
+ pthread_create(&thread_B, NULL, waiter, dummy);
+ pthread_create(&thread_C, NULL, waiter, dummy);
+
+ while (dummy->val != 3) {
+ while (parcObject_TryLock(dummy) == false) {
+ ;
+ }
+ parcObject_NotifyAll(dummy);
+ parcObject_Unlock(dummy);
+ }
+
+ pthread_join(thread_A, NULL);
+// pthread_join(thread_B, NULL);
+// pthread_join(thread_C, NULL);
+
+ assertTrue(dummy->val == 3, "Expected the counter to be 3, actual %d", dummy->val);
+
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+static void *
+decrement(void *data)
+{
+ _DummyObject *dummy = data;
+
+ while (parcObject_TryLock(dummy) == false) {
+ ;
+ }
+ while (dummy->val < 12) {
+ parcObject_Wait(dummy);
+ dummy->val--;
+ }
+ parcObject_Unlock(dummy);
+
+ return data;
+}
+
+LONGBOW_TEST_CASE(WaitNotify, parcObject_WaitNotify2)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ dummy->val = 0;
+
+ pthread_t thread_A;
+ pthread_create(&thread_A, NULL, decrement, dummy);
+
+ dummy->val = 2;
+ while (parcObject_TryLock(dummy) == false) {
+ ;
+ }
+ while (dummy->val <= 12) {
+ parcObject_Notify(dummy);
+ dummy->val += 2;
+ }
+ parcObject_Unlock(dummy);
+
+ pthread_join(thread_A, NULL);
+
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(WaitNotify, parcObject_WaitUntil)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ dummy->val = 0;
+
+ time_t now;
+ time_t then;
+ time(&then);
+ if (parcObject_Lock(dummy)) {
+ struct timespec future;
+ future.tv_sec = then + 3;
+ future.tv_nsec = 0;
+ parcObject_WaitUntil(dummy, &future);
+
+ time(&now);
+ long expected = now - 1; // Subtract 1 because the future may have been computed at the 999,999,999 nanosecond mark.
+ assertTrue(now >= expected, "Expected now %ld, to be later than than %ld", now, expected);
+ parcObject_Unlock(dummy);
+ }
+
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_CASE(WaitNotify, parcObject_WaitFor)
+{
+ _DummyObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ dummy->val = 0;
+
+ time_t now;
+ time_t then;
+ time(&then);
+ if (parcObject_Lock(dummy)) {
+ uint64_t nanoSeconds = 1000000000;
+ parcObject_WaitFor(dummy, nanoSeconds);
+
+ time(&now);
+ now++; // Advance now by 1 because of the precision mismatch between gettimeofday and nanosecond resolution of parcObject_WaitFor
+ assertTrue(now >= then + (nanoSeconds / 1000000000),
+ "Expected now %ld, to be later than time %" PRIu64, now, then + (nanoSeconds / 1000000000));
+ parcObject_Unlock(dummy);
+ }
+
+ parcObject_Release((PARCObject **) &dummy);
+}
+
+LONGBOW_TEST_FIXTURE(Fail)
+{
+}
+
+typedef struct {
+ PARCObject *value;
+} TestData;
+
+LONGBOW_TEST_FIXTURE_SETUP(Fail)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ data->value = parcObject_CreateInstance(_DummyObjectNoHash);
+ if (data->value == NULL) {
+ return LONGBOW_STATUS_SETUP_FAILED;
+ }
+ longBowTestCase_SetClipBoardData(testCase, data);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Fail)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ parcObject_Release(&data->value);
+ parcMemory_Deallocate((void **) &data);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+
+ parcMemory_SetInterface(_originalMemoryProvider);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, _parcObject_PrefixLength_10000000);
+ LONGBOW_RUN_TEST_CASE(Performance, parcObject_CreateRelease);
+ LONGBOW_RUN_TEST_CASE(Performance, parcObject_Create);
+ LONGBOW_RUN_TEST_CASE(Performance, parcObject_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ parcMemory_SetInterface(&PARCStdlibMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, _parcObject_PrefixLength_10000000)
+{
+ // Test that the result is a multiple of the alignment value and greater than the size of _PARCObjectHeader.
+
+ // Compute the power of 2 value of sizeof(void *)
+ unsigned int v = sizeof(void *);
+ unsigned int r = 0; // r will be lg(v)
+
+ while (v >>= 1) {
+ r++;
+ }
+
+ PARCObjectDescriptor descriptor;
+
+ for (int i = r; i < 20; i++) {
+ descriptor.objectAlignment = 1 << i;
+ size_t actual = _parcObject_PrefixLength(&descriptor);
+ assertTrue((actual & (descriptor.objectAlignment - 1)) == 0,
+ "Alignment needs to be a multiple of %u", descriptor.objectAlignment);
+ }
+}
+
+#define OBJECT_COUNT 10000000
+#define OBJECT_SIZE 1200
+
+typedef struct { char bytes[OBJECT_SIZE]; } PerformanceObject;
+
+parcObject_Override(PerformanceObject, PARCObject);
+
+LONGBOW_TEST_CASE(Performance, parcObject_CreateRelease)
+{
+ for (int i = 0; i < OBJECT_COUNT; i++) {
+ PARCObject *object = parcObject_CreateInstanceImpl(&PerformanceObject_Descriptor);
+
+ PARCObject *object1 = parcObject_Acquire(object);
+ PARCObject *object2 = parcObject_Acquire(object);
+ parcObject_Release(&object1);
+ parcObject_Release(&object2);
+
+ parcObject_Release(&object);
+ }
+}
+
+void *objects[OBJECT_COUNT];
+
+LONGBOW_TEST_CASE(Performance, parcObject_AcquireRelease)
+{
+ PARCObject *object = parcObject_CreateInstanceImpl(&PerformanceObject_Descriptor);
+
+ for (int i = 0; i < OBJECT_COUNT; i++) {
+ objects[i] = parcObject_Acquire(object);
+ }
+
+ for (int i = 0; i < OBJECT_COUNT; i++) {
+ parcObject_Release(&objects[i]);
+ }
+
+ parcObject_Release(&object);
+}
+
+LONGBOW_TEST_CASE(Performance, parcObject_Create)
+{
+ for (int i = 0; i < OBJECT_COUNT; i++) {
+ objects[i] = parcObject_CreateInstanceImpl(&PerformanceObject_Descriptor);
+ }
+
+ for (int i = 0; i < OBJECT_COUNT; i++) {
+ parcObject_Release(&objects[i]);
+ }
+}
+
+LONGBOW_TEST_FIXTURE(Meta)
+{
+ LONGBOW_RUN_TEST_CASE(Meta, _metaDestructor_True);
+ LONGBOW_RUN_TEST_CASE(Meta, _metaDestructor_False);
+ LONGBOW_RUN_TEST_CASE(Meta, _metaDestructor_None);
+
+ LONGBOW_RUN_TEST_CASE(Meta, parcObjectDescriptor_Create);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Meta)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ _DummyObject *data;
+ parcMemory_MemAlign((void **) &data, sizeof(void *), sizeof(_DummyObject));
+ data->val = 10;
+ longBowTestCase_SetClipBoardData(testCase, data);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Meta)
+{
+ _DummyObject *data = longBowTestCase_GetClipBoardData(testCase);
+ parcMemory_Deallocate((void **) &data);
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ parcMemory_SetInterface(_originalMemoryProvider);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Meta, parcObjectDescriptor_Create)
+{
+ const PARCObjectDescriptor *interface = parcObjectDescriptor_Create("Meta",
+ sizeof(struct timeval), sizeof(void*),
+ true,
+ _meta_destructor_true, NULL, _meta_copy, _meta_toString,
+ _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL,
+ &PARCObject_Descriptor, NULL);
+
+ assertNotNull(interface, "Expected interface instance to be allocated correctly.");
+
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &interface);
+ assertNull(interface, "Expected parcObjectDescriptor_Destroy to NULL the input pointer");
+}
+
+LONGBOW_TEST_CASE(Meta, _metaDestructor_True)
+{
+ const PARCObjectDescriptor *interface =
+ parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true,
+ _meta_destructor_true, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL,
+ &PARCObject_Descriptor, NULL);
+ _DummyObject *data = longBowTestCase_GetClipBoardData(testCase);
+ bool actual = _parcObject_Destructor(interface, (PARCObject **) &data);
+
+ assertTrue(actual, "Expected destructor to return true.");
+
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &interface);
+}
+
+LONGBOW_TEST_CASE(Meta, _metaDestructor_False)
+{
+ const PARCObjectDescriptor *descriptor =
+ parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true,
+ _meta_destructor_false, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL,
+ &PARCObject_Descriptor, NULL);
+ _DummyObject *data = longBowTestCase_GetClipBoardData(testCase);
+ bool actual = _parcObject_Destructor(descriptor, (PARCObject **) &data);
+
+ assertNull(data, "Expected destructor function to have been called to nullify the reference.");
+ assertFalse(actual, "Expected destructor to return false.");
+
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor);
+}
+
+LONGBOW_TEST_CASE(Meta, _metaDestructor_None)
+{
+ const PARCObjectDescriptor *interface = parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL, &PARCObject_Descriptor, NULL);
+ _DummyObject *data = longBowTestCase_GetClipBoardData(testCase);
+ _parcObject_Destructor(interface, (void **) &data);
+
+ assertNotNull(data, "Expected destructor function to have been called to nullify the reference.");
+
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &interface);
+}
+
+LONGBOW_TEST_FIXTURE(PARCObjectDescriptor)
+{
+ LONGBOW_RUN_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_Create);
+ LONGBOW_RUN_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_CreateExtension);
+ LONGBOW_RUN_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_GetSuperType);
+ LONGBOW_RUN_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_GetTypeState);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(PARCObjectDescriptor)
+{
+ longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(PARCObjectDescriptor)
+{
+ int initialAllocations = longBowTestCase_GetInt(testCase, "initialAllocations");
+
+ uint32_t outstandingAllocations = parcMemory_Outstanding() - initialAllocations;
+
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_Create)
+{
+ const PARCObjectDescriptor *descriptor = parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL, &PARCObject_Descriptor, NULL);
+
+ parcObjectDescriptor_Destroy((PARCObjectDescriptor **) &descriptor);
+}
+
+LONGBOW_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_CreateExtension)
+{
+ PARCObjectDescriptor *descriptor = parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL, &PARCObject_Descriptor, NULL);
+
+ PARCObjectDescriptor *extension = parcObjectDescriptor_CreateExtension(descriptor, "Extension");
+
+ parcObjectDescriptor_Destroy(&extension);
+ parcObjectDescriptor_Destroy(&descriptor);
+}
+
+LONGBOW_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_GetSuperType)
+{
+ PARCObjectDescriptor *descriptor = parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, _meta_copy, _meta_toString, _meta_equals, _meta_compare, _meta_hashCode, _meta_toJson, NULL, &PARCObject_Descriptor, NULL);
+
+ const PARCObjectDescriptor *superType = parcObjectDescriptor_GetSuperType(descriptor);
+
+ assertTrue(superType == &PARCObject_Descriptor, "Expected a pointer to PARCObject_Descriptor");
+
+ parcObjectDescriptor_Destroy(&descriptor);
+}
+
+LONGBOW_TEST_CASE(PARCObjectDescriptor, parcObjectDescriptor_GetTypeState)
+{
+ PARCObjectDescriptor *descriptor = parcObjectDescriptor_Create("Meta", sizeof(struct timeval), sizeof(void*), true,
+ NULL, NULL, _meta_copy, _meta_toString, _meta_equals,
+ _meta_compare, _meta_hashCode, _meta_toJson, NULL,
+ &PARCObject_Descriptor,
+ (PARCObjectTypeState *) &PARCObject_Descriptor);
+
+ PARCObjectTypeState *state = parcObjectDescriptor_GetTypeState(descriptor);
+
+ assertTrue(state == &PARCObject_Descriptor, "Expected a pointer to PARCObject_Descriptor");
+
+ parcObjectDescriptor_Destroy(&descriptor);
+}
+
+LONGBOW_TEST_FIXTURE(StaticObjects)
+{
+ LONGBOW_RUN_TEST_CASE(StaticObjects, parcObject_WrapImpl);
+ LONGBOW_RUN_TEST_CASE(StaticObjects, parcObject_InitInstanceImpl);
+ LONGBOW_RUN_TEST_CASE(StaticObjects, parcObject_InitAndClearInstanceImpl);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(StaticObjects)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(StaticObjects)
+{
+ parcMemory_SetInterface(_originalMemoryProvider);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(StaticObjects, parcObject_WrapImpl)
+{
+ char *origin = (char[parcObject_TotalSize(sizeof(void*), 10)]) { 0 };
+
+ PARCObject *result = parcObject_WrapImpl(origin, &parcObject_DescriptorName(PARCObject));
+
+ parcObject_AssertValid(result);
+
+ parcObject_Release(&result);
+}
+
+PARCObject *globalObject = parcObject_Instance(PARCObject, sizeof(void*), 10);
+
+LONGBOW_TEST_CASE(StaticObjects, parcObject_InitInstanceImpl)
+{
+ parcObject_InitInstanceImpl(globalObject, &PARCObject_Descriptor);
+
+ parcObject_AssertValid(globalObject);
+
+// parcObject_Release(&globalObject);
+}
+
+LONGBOW_TEST_CASE(StaticObjects, parcObject_InitAndClearInstanceImpl)
+{
+ parcObject_InitAndClearInstanceImpl(globalObject, &PARCObject_Descriptor);
+
+ parcObject_AssertValid(globalObject);
+
+// parcObject_Release(&globalObject);
+}
+
+LONGBOW_TEST_FIXTURE(Synchronization)
+{
+ LONGBOW_RUN_TEST_CASE(Synchronization, parcObject_SynchronizeBegin);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Synchronization)
+{
+ _originalMemoryProvider = parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Synchronization)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+
+ parcMemory_SetInterface(_originalMemoryProvider);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Synchronization, parcObject_SynchronizeBegin)
+{
+ PARCObject *dummy = parcObject_CreateInstance(_DummyObject);
+
+ bool result = parcObject_BarrierSet(dummy);
+ assertTrue(result, "Expected parcObject_BarrierSet to always return true.");
+
+ _PARCObjectHeader *header = _parcObject_Header(dummy);
+ assertTrue(header->barrier, "Expected the header barrier to be set.");
+
+ result = parcObject_BarrierUnset(dummy);
+ assertFalse(result, "Expected parcObject_BarrierUnset to always return false.");
+ assertFalse(header->barrier, "Expected the header barrier to NOT be set.");
+
+ parcObject_Release(&dummy);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcObject);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
diff --git a/libparc/parc/algol/test/test_parc_PathName.c b/libparc/parc/algol/test/test_parc_PathName.c
new file mode 100755
index 00000000..b596aaa2
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_PathName.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ *
+ */
+#include "../parc_PathName.c"
+#include <LongBow/unit-test.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_SafeMemory.h"
+#include <parc/testing/parc_ObjectTesting.h>
+
+#define PATH_SEGMENT "A"
+
+LONGBOW_TEST_RUNNER(parc_PathName)
+{
+ // 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(Local);
+ LONGBOW_RUN_TEST_FIXTURE(AcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_PathName)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_PathName)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(AcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcPathName_Create);
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcPathName_Release);
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcPathName_AcquireRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease)
+{
+ 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(AcquireRelease, parcPathName_Create)
+{
+ PARCPathName *pathName = parcPathName_Create();
+ assertNotNull(pathName, "Expected a non-null pointer");
+
+ parcPathName_Release(&pathName);
+ assertNull(pathName, "Expected parcPathName_Release to null the pointer");
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcPathName_Release)
+{
+ PARCPathName *pathName = parcPathName_Create();
+ assertNotNull(pathName, "Expected a non-null pointer");
+
+ parcPathName_Release(&pathName);
+ assertNull(pathName, "Expected parcPathName_Release to null the pointer");
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcPathName_AcquireRelease)
+{
+ PARCPathName *original = parcPathName_Create();
+ assertNotNull(original, "Expected non-null result from parcPathName_Create()");
+
+ PARCPathName *reference = parcPathName_Acquire(original);
+ assertTrue(original == reference, "Expected the reference to be equal to the original.");
+
+ parcPathName_Release(&original);
+ assertNull(original, "Expected parcDeque_Release to null the pointer");
+
+ parcPathName_Append(reference, (void *) "Hello");
+ size_t expected = 1;
+ size_t actual = parcPathName_Size(reference);
+ assertTrue(expected == actual,
+ "Expected size %zd, actual %zd", expected, actual);
+ parcPathName_Release(&reference);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Create);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Size);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Append);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Prepend);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_IsAbsolute);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_MakeAbsolute);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Parse_AbsolutePath);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Parse_AbsolutePath_Limited);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Parse_RelativePath);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_ToString_AbsolutePath);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_ToString_RelativePath);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Head);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Tail);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Tail_ExceedsLength);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcPathName_Copy);
+}
+
+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, parcPathName_Size)
+{
+ char *path = "/a/b/c";
+ PARCPathName *pathName = parcPathName_Parse(path);
+ assertNotNull(pathName, "Expected a non-null pointer");
+ assertTrue(pathName->isAbsolute, "Expected the PARCPathName to be absolute.");
+
+ assertTrue(parcPathName_Size(pathName) == 3, "Expected 3, actual %zu", parcPathName_Size(pathName));
+ parcPathName_Release(&pathName);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Prepend)
+{
+ PARCPathName *pathName = parcPathName_Create();
+ size_t size = 1000;
+
+ char expected[10];
+ for (size_t i = 0; i < size; i++) {
+ sprintf(expected, "%zd", i);
+ parcPathName_Prepend(pathName, expected);
+ }
+ assertNotNull(pathName, "Expected a non-null pointer");
+
+ size_t actual = parcPathName_Size(pathName);
+ assertTrue(size == actual,
+ "Expected %zd, actual %zd", size, actual);
+
+ for (size_t i = 0; i < size; i++) {
+ sprintf(expected, "%zd", size - i - 1);
+ char *segment = parcDeque_GetAtIndex(pathName->path, i);
+ assertTrue(strcmp(segment, expected) == 0,
+ "Expected %s, actual %s", expected, segment);
+ }
+
+ parcPathName_Release(&pathName);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Append)
+{
+ PARCPathName *pathName = parcPathName_Create();
+ size_t size = 1000;
+
+ char expected[10];
+ for (size_t i = 0; i < size; i++) {
+ sprintf(expected, "%zd", i);
+ parcPathName_Append(pathName, expected);
+ }
+ assertNotNull(pathName, "Expected a non-null pointer");
+
+ size_t actual = parcPathName_Size(pathName);
+ assertTrue(size == actual,
+ "Expected %zd, actual %zd", size, actual);
+
+ for (size_t i = 0; i < size; i++) {
+ sprintf(expected, "%zd", i);
+ char *segment = parcDeque_GetAtIndex(pathName->path, i);
+ assertTrue(strcmp(segment, expected) == 0,
+ "Expected %s, actual %s", expected, segment);
+ }
+
+ parcPathName_Release(&pathName);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Create)
+{
+ PARCPathName *pathName = parcPathName_Create();
+ assertNotNull(pathName, "Expected a non-null pointer");
+
+ parcPathName_Release(&pathName);
+ assertNull(pathName, "Expected parcPathName_Release to null the pointer");
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_IsAbsolute)
+{
+ char *path = "/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/aa/bb/cc/dd/ee/ff/gg/hh/ii/jj/kk/ll/mm/nn/oo/pp/qq/rr/ss/tt/uu/vv/ww/xx/yy/zz";
+ PARCPathName *pathName = parcPathName_Parse(path);
+ assertNotNull(pathName, "Expected a non-null pointer");
+ assertTrue(parcPathName_IsAbsolute(pathName), "Expected the PARCPathName to be absolute.");
+
+ parcPathName_Release(&pathName);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_MakeAbsolute)
+{
+#define PATH "a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z"
+ char *expected = PATH;
+ PARCPathName *pathName = parcPathName_Parse(expected);
+ assertNotNull(pathName, "Expected a non-null pointer");
+ assertFalse(pathName->isAbsolute, "Expected the PARCPathName to be relative.");
+
+ parcPathName_MakeAbsolute(pathName, true);
+
+ char *actual = parcPathName_ToString(pathName);
+ assertTrue(strcmp("/" PATH, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+ parcPathName_Release(&pathName);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Parse_AbsolutePath)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ for (int i = 0; i < 1000; i++) {
+ parcBufferComposer_Format(composer, "/%d", i);
+ }
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *path = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ PARCPathName *pathName = parcPathName_Parse(path);
+ assertNotNull(pathName, "Expected a non-null pointer");
+ assertTrue(pathName->isAbsolute, "Expected the PARCPathName to be absolute.");
+
+
+ char *actual = parcPathName_ToString(pathName);
+ assertTrue(strcmp(path, actual) == 0, "Expected %s, actual %s", path, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcMemory_Deallocate((void **) &path);
+
+ parcPathName_Release(&pathName);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Parse_AbsolutePath_Limited)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ for (int i = 0; i < 10; i++) {
+ parcBufferComposer_Format(composer, "/%d", i);
+ }
+ parcBufferComposer_Format(composer, "?hello world");
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *path = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ size_t limit = strchr(path, '?') - path;
+ PARCPathName *pathName = parcPathName_ParseToLimit(limit, path);
+
+ assertNotNull(pathName, "Expected a non-null pointer");
+ assertTrue(pathName->isAbsolute, "Expected the PARCPathName to be absolute.");
+
+ path[limit] = 0;
+ char *actual = parcPathName_ToString(pathName);
+ assertTrue(strcmp(path, actual) == 0, "Expected %s, actual %s", path, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+ parcMemory_Deallocate((void **) &path);
+
+ parcPathName_Release(&pathName);
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Parse_RelativePath)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ for (int i = 0; i < 1000; i++) {
+ parcBufferComposer_Format(composer, "%d/", i);
+ }
+ parcBufferComposer_Format(composer, "%d", 1000);
+
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ char *expected = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+
+ PARCPathName *pathName = parcPathName_Parse(expected);
+ assertNotNull(pathName, "Expected a non-null pointer");
+ assertFalse(pathName->isAbsolute, "Expected the PARCPathName to be relative.");
+
+ char *actual = parcPathName_ToString(pathName);
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+ parcMemory_Deallocate((void **) &expected);
+
+ parcPathName_Release(&pathName);
+
+ parcBufferComposer_Release(&composer);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_ToString_AbsolutePath)
+{
+ char *path = "/a/b/c";
+ PARCPathName *pathName = parcPathName_Parse(path);
+ assertNotNull(pathName, "Expected a non-null pointer");
+ assertTrue(pathName->isAbsolute, "Expected the PARCPathName to be absolute.");
+
+ char *actual = parcPathName_ToString(pathName);
+
+ assertTrue(strcmp(path, actual) == 0, "Expected '%s' actual '%s'", path, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcPathName_Release(&pathName);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_ToString_RelativePath)
+{
+ char *path = "a/b/c";
+ PARCPathName *pathName = parcPathName_Parse(path);
+ assertNotNull(pathName, "Expected a non-null pointer");
+ assertFalse(pathName->isAbsolute, "Expected the PARCPathName to be relative.");
+
+ char *actual = parcPathName_ToString(pathName);
+
+ assertTrue(strcmp(path, actual) == 0, "Expected '%s' actual '%s'", path, actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcPathName_Release(&pathName);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Head)
+{
+ PARCPathName *original = parcPathName_Parse("/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT);
+ assertNotNull(original, "Expected a non-null pointer");
+
+ PARCPathName *expected = parcPathName_Parse("/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT);
+ PARCPathName *actual = parcPathName_Head(original, 3);
+
+ assertTrue(parcPathName_Equals(expected, actual),
+ "expected did not match actual");
+
+ parcPathName_Release(&original);
+ parcPathName_Release(&expected);
+ parcPathName_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Tail)
+{
+ PARCPathName *original = parcPathName_Parse("/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT);
+ assertNotNull(original, "Expected a non-null pointer");
+
+ PARCPathName *expected = parcPathName_Parse(PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT);
+ PARCPathName *actual = parcPathName_Tail(original, 3);
+
+ assertTrue(parcPathName_Equals(expected, actual),
+ "expected did not match actual");
+
+ parcPathName_Release(&original);
+ parcPathName_Release(&expected);
+ parcPathName_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Tail_ExceedsLength)
+{
+ PARCPathName *original = parcPathName_Parse("/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT "/" PATH_SEGMENT);
+ assertNotNull(original, "Expected a non-null pointer");
+
+ PARCPathName *actual = parcPathName_Tail(original, 10000000);
+
+ parcPathName_MakeAbsolute(original, false);
+
+ assertTrue(parcPathName_Equals(original, actual),
+ "expected did not match actual");
+
+ parcPathName_Release(&original);
+ parcPathName_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Equals)
+{
+ PARCPathName *x = parcPathName_Parse("/a/b/c/d/");
+ PARCPathName *y = parcPathName_Parse("/a/b/c/d/");
+ PARCPathName *z = parcPathName_Parse("/a/b/c/d/");
+ PARCPathName *u1 = parcPathName_Parse("/a/b/c/d/e");
+ PARCPathName *u2 = parcPathName_Parse("/a/b/c/");
+ PARCPathName *u3 = parcPathName_Parse("a/b/c/");
+
+ parcObjectTesting_AssertEqualsFunction(parcPathName_Equals, x, y, z, u1, u2, u3, NULL);
+
+ parcPathName_Release(&x);
+ parcPathName_Release(&y);
+ parcPathName_Release(&z);
+ parcPathName_Release(&u1);
+ parcPathName_Release(&u2);
+ parcPathName_Release(&u3);
+}
+
+LONGBOW_TEST_CASE(Global, parcPathName_Copy)
+{
+ PARCPathName *x = parcPathName_Parse("/a/b/c/d/");
+ PARCPathName *y = parcPathName_Copy(x);
+
+ assertTrue(parcPathName_Equals(x, y), "Expected the copy to be equal to the original.");
+
+ parcPathName_Release(&x);
+ parcPathName_Release(&y);
+}
+
+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(parc_PathName);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_PriorityQueue.c b/libparc/parc/algol/test/test_parc_PriorityQueue.c
new file mode 100644
index 00000000..d42066e4
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_PriorityQueue.c
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <inttypes.h>
+
+#include "../parc_PriorityQueue.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_PriorityQueue)
+{
+ // 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(parc_PriorityQueue)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_PriorityQueue)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Add);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Add_Expand);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Clear);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Clear_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_ParcFreeDestroyer);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Peek);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Poll);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Peek_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Poll_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Size);
+ LONGBOW_RUN_TEST_CASE(Global, parcPriorityQueue_Uint64CompareTo);
+}
+
+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, parcPriorityQueue_Add)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 60, 70, 50, 71, 72, 55 };
+ size_t count = 6;
+
+ for (int i = 0; i < count; i++) {
+ parcPriorityQueue_Add(queue, &data[i]);
+ }
+
+ assertTrue(parcPriorityQueue_Size(queue) == count, "Wrong size got %zu expected %zu", parcPriorityQueue_Size(queue), count);
+ parcPriorityQueue_Destroy(&queue);
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Add_Expand)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ size_t capacity = queue->capacity;
+ for (int i = 0; i <= capacity; i++) {
+ parcPriorityQueue_Add(queue, &capacity);
+ }
+
+ assertTrue(capacity < queue->capacity, "Did not expand queue before %zu after %zu", capacity, queue->capacity);
+ parcPriorityQueue_Destroy(&queue);
+}
+
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Clear)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 60, 70, 50, 71, 72, 55 };
+ size_t count = 6;
+
+ for (int i = 0; i < count; i++) {
+ parcPriorityQueue_Add(queue, &data[i]);
+ }
+
+ parcPriorityQueue_Clear(queue);
+
+ assertTrue(parcPriorityQueue_Size(queue) == 0, "Wrong size got %zu expected %d", parcPriorityQueue_Size(queue), 0);
+ parcPriorityQueue_Destroy(&queue);
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Clear_Destroy)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, parcPriorityQueue_ParcFreeDestroyer);
+ uint64_t *value = parcMemory_Allocate(sizeof(uint64_t));
+ assertNotNull(value, "parcMemory_Allocate(%zu) returned NULL", sizeof(uint64_t));
+ *value = 1;
+ parcPriorityQueue_Add(queue, value);
+
+ parcPriorityQueue_Clear(queue);
+
+ assertTrue(parcPriorityQueue_Size(queue) == 0, "Wrong size got %zu expected %d", parcPriorityQueue_Size(queue), 0);
+ parcPriorityQueue_Destroy(&queue);
+
+ assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance after clear with destroy: %u", parcMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Create)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_ParcFreeDestroyer)
+{
+ size_t before_balance = parcMemory_Outstanding();
+ uint64_t *a = parcMemory_Allocate(sizeof(uint64_t));
+ assertNotNull(a, "parcMemory_Allocate(%zu) returned NULL", sizeof(uint64_t));
+ *a = 1;
+ parcPriorityQueue_ParcFreeDestroyer((void **) &a);
+ size_t after_balance = parcMemory_Outstanding();
+ assertTrue(a == NULL, "Did not null double pointer");
+ assertTrue(before_balance == after_balance, "Memory imbalance after destroy: before %zu after %zu", before_balance, after_balance);
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Peek)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 60, 70, 50, 71, 72, 55 };
+ size_t count = 6;
+
+ for (int i = 0; i < count; i++) {
+ parcPriorityQueue_Add(queue, &data[i]);
+ }
+
+ uint64_t *test = parcPriorityQueue_Peek(queue);
+
+ assertTrue(*test == 50, "Wrong head element, expected 50 got %" PRIu64 "", *test);
+ assertTrue(parcPriorityQueue_Size(queue) == count, "Queue should not have shunk, size %zu expected %zu", parcPriorityQueue_Size(queue), count);
+ parcPriorityQueue_Destroy(&queue);
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Poll)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 60, 70, 50, 71, 72, 55 };
+ size_t count = 6;
+
+ for (int i = 0; i < count; i++) {
+ parcPriorityQueue_Add(queue, &data[i]);
+ }
+
+ uint64_t *test = parcPriorityQueue_Poll(queue);
+
+ assertTrue(*test == 50, "Wrong head element, expected 50 got %" PRIu64 "", *test);
+ assertTrue(queue->size == count - 1, "Queue should have shunk, size %zu expected %zu", queue->size, count - 1);
+ parcPriorityQueue_Destroy(&queue);
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Peek_Empty)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t *test = parcPriorityQueue_Peek(queue);
+ assertNull(test, "Peek on empty queue should return null, got %p", (void *) test);
+ parcPriorityQueue_Destroy(&queue);
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Poll_Empty)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t *test = parcPriorityQueue_Poll(queue);
+ assertNull(test, "Poll on empty queue should return null, got %p", (void *) test);
+ parcPriorityQueue_Destroy(&queue);
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Size)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcPriorityQueue_Uint64CompareTo)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_BubbleUp_True);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_BubbleUp_False);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_Expand);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_LeftChildIndex);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_ParentIndex);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_RightChildIndex);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_Swap);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleDown);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleLeftChild_True);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleLeftChild_False);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case1_True);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case2_True);
+ LONGBOW_RUN_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case1_False);
+}
+
+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, parcPriorityQueue_BubbleUp_True)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 50, 6 };
+
+ queue->array[0].data = &data[0];
+ queue->array[1].data = &data[1];
+ queue->size = 2;
+
+ _bubbleUp(queue, 1);
+ assertTrue(queue->array[0].data == &data[1], "Element 6 did not make it to the root");
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_BubbleUp_False)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 50, 60 };
+
+ queue->array[0].data = &data[0];
+ queue->array[1].data = &data[1];
+ queue->size = 2;
+
+ _bubbleUp(queue, 1);
+ assertTrue(queue->array[0].data == &data[0], "Element 60 did not stay as child");
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_Expand)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ size_t before_capacity = queue->capacity;
+ _expand(queue);
+ size_t after_capacity = queue->capacity;
+
+ assertTrue(before_capacity < after_capacity, "Expected after capacity %zu to be larger than before %zu", after_capacity, before_capacity);
+ parcPriorityQueue_Destroy(&queue);
+}
+
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_LeftChildIndex)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_ParentIndex)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_RightChildIndex)
+{
+ testUnimplemented("");
+}
+
+/**
+ * Swaps two elements
+ */
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_Swap)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 50, 6 };
+
+ queue->array[0].data = &data[0];
+ queue->array[1].data = &data[1];
+ queue->size = 2;
+
+ _swap(queue, 0, 1);
+ assertTrue(queue->array[0].data == &data[1], "array[0] does not equal data[1]: %p != %p",
+ (void *) queue->array[0].data, (void *) &data[1]);
+ assertTrue(queue->array[1].data == &data[0], "array[1] does not equal data[0]: %p != %p",
+ (void *) queue->array[1].data, (void *) &data[0]);
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+/**
+ * Tests each case in TrickleDown:
+ * - right child exists, then
+ * - no right child, only left child, then
+ * - no child
+ *
+ * 60 50
+ * / \ / \
+ * 70 50 ====> 70 55
+ * / \ / \ / \ / \
+ * 71 72 55 x 71 72 60 x
+ */
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleDown)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 60, 70, 50, 71, 72, 55 };
+
+ queue->size = 6;
+ for (int i = 0; i < queue->size; i++) {
+ queue->array[i].data = &data[i];
+ }
+
+ _trickleDown(queue, 0);
+ assertTrue(*((uint64_t *) queue->array[0].data) == 50,
+ "Root not 50, got %" PRIu64 "\n",
+ (uint64_t) *((uint64_t *) queue->array[0].data));
+ assertTrue(*((uint64_t *) queue->array[2].data) == 55,
+ "Right not 55, got %" PRIu64 "\n",
+ (uint64_t) *((uint64_t *) queue->array[2].data));
+ assertTrue(*((uint64_t *) queue->array[5].data) == 60,
+ "Last not 60, got %" PRIu64 "\n",
+ (uint64_t) *((uint64_t *) queue->array[5].data));
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+/**
+ * Tests the TRUE case of this condition
+ *
+ * Case 3: Left child exists (right does not) and l.value < n.value
+ * In this case, swap(n.index, l.index) and set n.index = l.index
+ * 50 6
+ * / \ ===> / \
+ * 6 x 50 x
+ */
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleLeftChild_True)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 50, 6 };
+
+ queue->array[0].data = &data[0];
+ queue->array[1].data = &data[1];
+ queue->size = 2;
+
+ size_t nextElementIndex = _trickleLeftChild(queue, 0, 1);
+ assertTrue(nextElementIndex == 1, "nextElementIndex should have been left child 1, got %zu\n", nextElementIndex);
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+/**
+ * Tests the FALSE case of this condition
+ *
+ * Case 3: Left child exists (right does not) and l.value < n.value
+ * In this case, swap(n.index, l.index) and set n.index = l.index
+ * 50 6
+ * / \ ===> / \
+ * 6 x 50 x
+ */
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleLeftChild_False)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 6, 50 };
+
+ queue->array[0].data = &data[0];
+ queue->array[1].data = &data[1];
+ queue->size = 2;
+
+ size_t nextElementIndex = _trickleLeftChild(queue, 0, 1);
+ assertTrue(nextElementIndex == 0, "nextElementIndex should have been root 0, got %zu\n", nextElementIndex);
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+
+/**
+ * Tests the TRUE case
+ *
+ * Case 1: Right child exists and r.value < n.value && r.value < l.value
+ * In this case, swap(n.index, r.index) and set n.index = r.index.
+ * 50 6
+ * / \ ===> / \
+ * 9 6 9 50
+ */
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case1_True)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 50, 9, 6 };
+
+ queue->array[0].data = &data[0];
+ queue->array[1].data = &data[1];
+ queue->array[2].data = &data[2];
+ queue->size = 3;
+
+ size_t nextElementIndex = _trickleRightChild(queue, 0, 1, 2);
+ assertTrue(nextElementIndex == 2, "nextElementIndex should have been right 2, got %zu\n", nextElementIndex);
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+/**
+ * Tests the FALSE case
+ *
+ * Case 1: Right child exists and r.value < n.value && r.value < l.value
+ * In this case, swap(n.index, r.index) and set n.index = r.index.
+ * 50 6
+ * / \ ===> / \
+ * 9 6 9 50
+ */
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case1_False)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+
+ // r.value not < n.value
+ uint64_t data[] = { 6, 9, 50 };
+
+ queue->array[0].data = &data[0];
+ queue->array[1].data = &data[1];
+ queue->array[2].data = &data[2];
+ queue->size = 3;
+
+ size_t nextElementIndex = _trickleRightChild(queue, 0, 1, 2);
+ assertTrue(nextElementIndex == 0, "nextElementIndex should have been root 0, got %zu\n", nextElementIndex);
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+/**
+ * Tests the TRUE case
+ *
+ * Case 2: Right child exists and r.value < n.value && l.value <= r.value
+ * In this case swap(n.index, l.index) and set n.index = l.index
+ * This makes sense by transitivity that l <= r < n, so swap(n,l) satisfies the invariant.
+ * 50 6
+ * / \ ===> / \
+ * 6 9 50 9
+ */
+LONGBOW_TEST_CASE(Local, parcPriorityQueue_TrickleRightChild_Case2_True)
+{
+ PARCPriorityQueue *queue = parcPriorityQueue_Create(parcPriorityQueue_Uint64CompareTo, NULL);
+ uint64_t data[] = { 50, 6, 9 };
+
+ queue->array[0].data = &data[0];
+ queue->array[1].data = &data[1];
+ queue->array[2].data = &data[2];
+ queue->size = 3;
+
+ size_t nextElementIndex = _trickleRightChild(queue, 0, 1, 2);
+ assertTrue(nextElementIndex == 1, "nextElementIndex should have been left 1, got %zu\n", nextElementIndex);
+
+ parcPriorityQueue_Destroy(&queue);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_PriorityQueue);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Properties.c b/libparc/parc/algol/test/test_parc_Properties.c
new file mode 100644
index 00000000..994b8d8e
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Properties.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_Properties.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(parc_Properties)
+{
+ // 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);
+ LONGBOW_RUN_TEST_FIXTURE(Specialized);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Properties)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Properties)
+{
+ 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)
+{
+ PARCProperties *instance = parcProperties_Create();
+ assertNotNull(instance, "Expected non-null result from parcProperties_Create();");
+
+ parcObjectTesting_AssertAcquire(instance);
+
+ parcProperties_Release(&instance);
+ assertNull(instance, "Expected null result from parcProperties_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcProperties_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcProperties_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcProperties_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcProperties_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcProperties_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcProperties_IsValid);
+ LONGBOW_RUN_TEST_CASE(Global, parcProperties_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Global, parcProperties_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, parcProperties_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcProperties_Copy)
+{
+ PARCProperties *instance = parcProperties_Create();
+ PARCProperties *copy = parcProperties_Copy(instance);
+ assertTrue(parcProperties_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcProperties_Release(&instance);
+ parcProperties_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, parcProperties_Display)
+{
+ PARCProperties *instance = parcProperties_Create();
+ parcProperties_SetProperty(instance, "foo", "bar");
+ parcProperties_SetProperty(instance, "xyzzy", "plugh");
+
+ parcProperties_Display(instance, 0);
+ parcProperties_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcProperties_Equals)
+{
+ PARCProperties *x = parcProperties_Create();
+ PARCProperties *y = parcProperties_Create();
+ PARCProperties *z = parcProperties_Create();
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcProperties_Release(&x);
+ parcProperties_Release(&y);
+ parcProperties_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Global, parcProperties_HashCode)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcProperties_IsValid)
+{
+ PARCProperties *instance = parcProperties_Create();
+ assertTrue(parcProperties_IsValid(instance), "Expected parcProperties_Create to result in a valid instance.");
+
+ parcProperties_Release(&instance);
+ assertFalse(parcProperties_IsValid(instance), "Expected parcProperties_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcProperties_ToJSON)
+{
+ PARCProperties *instance = parcProperties_Create();
+
+ parcProperties_SetProperty(instance, "foo", "bar");
+ PARCJSON *json = parcProperties_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcProperties_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcProperties_ToString)
+{
+ PARCProperties *instance = parcProperties_Create();
+
+ parcProperties_SetProperty(instance, "foo", "bar");
+ parcProperties_SetProperty(instance, "bar", "baz");
+ char *string = parcProperties_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcProperties_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcProperties_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialized)
+{
+ LONGBOW_RUN_TEST_CASE(Specialized, parcProperties_SetProperty);
+ LONGBOW_RUN_TEST_CASE(Specialized, parcProperties_GetProperty);
+ LONGBOW_RUN_TEST_CASE(Specialized, parcProperties_GetPropertyDefault);
+ LONGBOW_RUN_TEST_CASE(Specialized, parcProperties_GetAsBoolean_true);
+ LONGBOW_RUN_TEST_CASE(Specialized, parcProperties_GetAsBoolean_false);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialized)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialized)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Specialized, parcProperties_SetProperty)
+{
+ PARCProperties *instance = parcProperties_Create();
+ char *expected = "bar";
+ parcProperties_SetProperty(instance, "foo", expected);
+
+ const char *actual = parcProperties_GetProperty(instance, "foo");
+ assertTrue(strcmp("bar", actual) == 0, "Expected %s, actual %s", expected, actual);
+
+ parcProperties_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialized, parcProperties_GetProperty)
+{
+ PARCProperties *instance = parcProperties_Create();
+ char *expected = "bar";
+ parcProperties_SetProperty(instance, "foo", expected);
+
+ const char *actual = parcProperties_GetProperty(instance, "foo");
+ assertTrue(strcmp("bar", actual) == 0, "Expected %s, actual %s", expected, actual);
+
+ parcProperties_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialized, parcProperties_GetPropertyDefault)
+{
+ PARCProperties *instance = parcProperties_Create();
+ char *expected = "bar";
+ parcProperties_SetProperty(instance, "foo", expected);
+
+ const char *actual = parcProperties_GetPropertyDefault(instance, "blurfl", "defaultValue");
+ assertTrue(strcmp("defaultValue", actual) == 0, "Expected %s, actual %s", "defaultValue", actual);
+
+ parcProperties_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialized, parcProperties_GetAsBoolean_true)
+{
+ PARCProperties *instance = parcProperties_Create();
+ char *expected = "true";
+ parcProperties_SetProperty(instance, "foo", expected);
+
+ bool actual = parcProperties_GetAsBoolean(instance, "foo", false);
+ assertTrue(actual, "Expected true");
+
+ parcProperties_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialized, parcProperties_GetAsBoolean_false)
+{
+ PARCProperties *instance = parcProperties_Create();
+ char *expected = "false";
+ parcProperties_SetProperty(instance, "foo", expected);
+
+ bool actual = parcProperties_GetAsBoolean(instance, "foo", true);
+ assertFalse(actual, "Expected false");
+
+ parcProperties_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Properties);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libparc/parc/algol/test/test_parc_RandomAccessFile.c b/libparc/parc/algol/test/test_parc_RandomAccessFile.c
new file mode 100644
index 00000000..796b69d8
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_RandomAccessFile.c
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_RandomAccessFile.c"
+
+#include <sys/param.h>
+
+#include <fcntl.h>
+
+#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(parcRandomAccessFile_RandomAccessFile)
+{
+ // 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(parcRandomAccessFile_RandomAccessFile)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parcRandomAccessFile_RandomAccessFile)
+{
+ 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)
+{
+ char dirname[] = "/tmp/RandomAccessFile_XXXXXX";
+ char filename[MAXPATHLEN];
+
+ char *temporaryDirectory = mkdtemp(dirname);
+ assertNotNull(temporaryDirectory, "tmp_dirname should not be null");
+ sprintf(filename, "%s/tmpfile", temporaryDirectory);
+
+ PARCFile *file = parcFile_Create(filename);
+ PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file);
+ assertNotNull(instance, "Expected non-null result from parcRandomAccessFile_Open();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcRandomAccessFile_Acquire, instance);
+
+ parcRandomAccessFile_Release(&instance);
+ assertNull(instance, "Expected null result from parcRandomAccessFile_Release();");
+
+ parcFile_Release(&file);
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_Display);
+ // XXX: Disable this test until fixed
+ //LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_ToString);
+}
+
+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, parcRandomAccessFile_Display)
+{
+ char dirname[] = "/tmp/RandomAccessFile_XXXXXX";
+ char filename[MAXPATHLEN];
+
+ char *temporaryDirectory = mkdtemp(dirname);
+ assertNotNull(temporaryDirectory, "tmp_dirname should not be null");
+ sprintf(filename, "%s/tmpfile", temporaryDirectory);
+
+ PARCFile *file = parcFile_Create(filename);
+ PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file);
+ parcFile_Release(&file);
+
+ parcRandomAccessFile_Display(instance, 0);
+ parcRandomAccessFile_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcRandomAccessFile_Equals)
+{
+ char dirname[] = "/tmp/RandomAccessFile_XXXXXX";
+ char filename[MAXPATHLEN];
+
+ char *temporaryDirectory = mkdtemp(dirname);
+ assertNotNull(temporaryDirectory, "tmp_dirname should not be null");
+
+ sprintf(filename, "%s/tmpfileX", temporaryDirectory);
+ PARCFile *fileX = parcFile_Create(filename);
+
+ sprintf(filename, "%s/tmpfileY", temporaryDirectory);
+ PARCFile *fileY = parcFile_Create(filename);
+
+ sprintf(filename, "%s/tmpfileZ", temporaryDirectory);
+ PARCFile *fileZ = parcFile_Create(filename);
+
+ PARCRandomAccessFile *x = parcRandomAccessFile_Open(fileX);
+ PARCRandomAccessFile *y = parcRandomAccessFile_Open(fileY);
+ PARCRandomAccessFile *z = parcRandomAccessFile_Open(fileZ);
+ parcFile_Release(&fileX);
+ parcFile_Release(&fileY);
+ parcFile_Release(&fileZ);
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcRandomAccessFile_Close(x);
+ parcRandomAccessFile_Close(y);
+ parcRandomAccessFile_Close(z);
+
+ parcRandomAccessFile_Release(&x);
+ parcRandomAccessFile_Release(&y);
+ parcRandomAccessFile_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Object, parcRandomAccessFile_IsValid)
+{
+ char dirname[] = "/tmp/RandomAccessFile_XXXXXX";
+ char filename[MAXPATHLEN];
+
+ char *temporaryDirectory = mkdtemp(dirname);
+ assertNotNull(temporaryDirectory, "tmp_dirname should not be null");
+ sprintf(filename, "%s/tmpfile", temporaryDirectory);
+
+ PARCFile *file = parcFile_Create(filename);
+ parcFile_CreateNewFile(file);
+
+ PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file);
+ parcFile_Release(&file);
+ assertTrue(parcRandomAccessFile_IsValid(instance), "Expected parcRandomAccessFile_Create to result in a valid instance.");
+
+ parcRandomAccessFile_Release(&instance);
+ assertFalse(parcRandomAccessFile_IsValid(instance), "Expected parcRandomAccessFile_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcRandomAccessFile_ToJSON)
+{
+ char dirname[] = "/tmp/RandomAccessFile_XXXXXX";
+ char filename[MAXPATHLEN];
+
+ char *temporaryDirectory = mkdtemp(dirname);
+ assertNotNull(temporaryDirectory, "tmp_dirname should not be null");
+ sprintf(filename, "%s/tmpfile", temporaryDirectory);
+
+ PARCFile *file = parcFile_Create(filename);
+ PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file);
+ parcFile_Release(&file);
+
+ PARCJSON *json = parcRandomAccessFile_ToJSON(instance);
+
+ const PARCJSONPair *pair = parcJSON_GetPairByName(json, "fname");
+ PARCJSONValue *value = parcJSONPair_GetValue(pair);
+ PARCBuffer *buffer = parcJSONValue_GetString(value);
+
+ char *string = parcBuffer_ToString(buffer);
+ assertTrue(strcmp(filename, string) == 0, "The file was stored correctly");
+
+ parcMemory_Deallocate(&string);
+
+ parcJSON_Release(&json);
+
+ parcRandomAccessFile_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcRandomAccessFile_ToString)
+{
+ char dirname[] = "/tmp/RandomAccessFile_XXXXXX";
+ char filename[MAXPATHLEN];
+
+ char *temporaryDirectory = mkdtemp(dirname);
+ assertNotNull(temporaryDirectory, "tmp_dirname should not be null");
+ sprintf(filename, "%s/tmpfile", temporaryDirectory);
+
+ PARCFile *file = parcFile_Create(filename);
+ PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file);
+ parcFile_Release(&file);
+
+ char *string = parcRandomAccessFile_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcRandomAccessFile_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcRandomAccessFile_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_Read);
+ LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_Write);
+ LONGBOW_RUN_TEST_CASE(Object, parcRandomAccessFile_Seek);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, parcRandomAccessFile_Read)
+{
+ char *fname = "tmpfile";
+
+ PARCFile *file = parcFile_Create(fname);
+
+ parcFile_CreateNewFile(file);
+ FILE *fp = fopen(fname, "w");
+ fseek(fp, 0, SEEK_SET);
+
+ uint8_t data[128];
+ for (int i = 0; i < 128; i++) {
+ data[i] = i;
+ }
+ fwrite(data, 1, 128, fp);
+ fclose(fp);
+
+ PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file);
+ parcFile_Release(&file);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(128);
+ size_t numBytes = parcRandomAccessFile_Read(instance, buffer);
+ assertTrue(numBytes == 128, "Expected 128 bytes to be read, but got %zu", numBytes);
+
+ parcBuffer_Flip(buffer);
+ uint8_t *bytes = parcBuffer_Overlay(buffer, parcBuffer_Remaining(buffer));
+ assertTrue(memcmp(data, bytes, 128) == 0, "Expected buffers to be equal");
+
+ parcBuffer_Release(&buffer);
+ parcRandomAccessFile_Close(instance);
+ parcRandomAccessFile_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcRandomAccessFile_Write)
+{
+ char *fname = "tmpfile";
+
+ PARCFile *file = parcFile_Create(fname);
+
+ parcFile_CreateNewFile(file);
+
+ uint8_t data[128];
+ for (int i = 0; i < 128; i++) {
+ data[i] = i;
+ }
+
+ PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file);
+ PARCBuffer *buffer = parcBuffer_Allocate(128);
+ parcBuffer_PutArray(buffer, 128, data);
+ parcBuffer_Flip(buffer);
+ size_t numBytes = parcRandomAccessFile_Write(instance, buffer);
+ assertTrue(numBytes == 128, "Expected 128 bytes to be read, but got %zu", numBytes);
+ parcBuffer_Release(&buffer);
+
+ parcRandomAccessFile_Close(instance);
+ parcRandomAccessFile_Release(&instance);
+
+ uint8_t bytes[128];
+ FILE *fp = fopen(fname, "r");
+ numBytes = fread(bytes, 1, 128, fp);
+ assertTrue(numBytes == 128, "Expected 128 bytes to be read, but got %zu", numBytes);
+
+ fclose(fp);
+
+ assertTrue(memcmp(data, bytes, 128) == 0, "Expected buffers to be equal");
+
+ parcFile_Release(&file);
+}
+
+LONGBOW_TEST_CASE(Object, parcRandomAccessFile_Seek)
+{
+ char *fname = "tmpfile";
+
+ PARCFile *file = parcFile_Create(fname);
+
+ parcFile_CreateNewFile(file);
+ FILE *fp = fopen(fname, "w");
+ fseek(fp, 0, SEEK_SET);
+
+ uint8_t data[128];
+ for (int i = 0; i < 128; i++) {
+ data[i] = i;
+ }
+ fwrite(data, 1, 128, fp);
+ fclose(fp);
+
+ PARCRandomAccessFile *instance = parcRandomAccessFile_Open(file);
+ PARCBuffer *buffer = parcBuffer_Allocate(128);
+ parcRandomAccessFile_Seek(instance, 64, PARCRandomAccessFilePosition_Start);
+ size_t numBytes = parcRandomAccessFile_Read(instance, buffer);
+ assertTrue(numBytes == 64, "Expected 64 bytes to be read, but got %zu", numBytes);
+
+ parcRandomAccessFile_Seek(instance, 0, PARCRandomAccessFilePosition_End);
+ parcBuffer_Flip(buffer);
+ numBytes = parcRandomAccessFile_Read(instance, buffer);
+ assertTrue(numBytes == 0, "Expected 0 bytes to be read, but got %zu", numBytes);
+
+ parcRandomAccessFile_Seek(instance, 0, PARCRandomAccessFilePosition_Start);
+ parcBuffer_Flip(buffer);
+ numBytes = parcRandomAccessFile_Read(instance, buffer);
+ assertTrue(numBytes == 128, "Expected 128 bytes to be read, but got %zu", numBytes);
+
+ parcBuffer_Release(&buffer);
+ parcRandomAccessFile_Close(instance);
+ parcRandomAccessFile_Release(&instance);
+
+ parcFile_Release(&file);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcRandomAccessFile_RandomAccessFile);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_ReadOnlyBuffer.c b/libparc/parc/algol/test/test_parc_ReadOnlyBuffer.c
new file mode 100644
index 00000000..19e250f8
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_ReadOnlyBuffer.c
@@ -0,0 +1,689 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_ReadOnlyBuffer.c"
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_ReadableBuffer)
+{
+ // 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);
+ LONGBOW_RUN_TEST_FIXTURE(CreateDestroy);
+ LONGBOW_RUN_TEST_FIXTURE(Errors);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_ReadableBuffer)
+{
+ 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_ReadableBuffer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+LONGBOW_TEST_FIXTURE(CreateDestroy)
+{
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Create);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Allocate_AcquireRelease);
+// LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Allocate_AcquireRelease_TooMany);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap_NULL);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap_WithOffset);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateDestroy)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateDestroy)
+{
+ 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(CreateDestroy, parcReadOnlyBuffer_Create)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(buffer);
+
+ assertTrue(parcReadOnlyBuffer_Position(actual) == 0, "Expected initial position to be 0.");
+ assertTrue(parcReadOnlyBuffer_Limit(actual) == 10, "Expected initial limit to be 10.");
+
+ parcReadOnlyBuffer_Release(&actual);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap_NULL)
+{
+ PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(parcBuffer_Wrap(NULL, 10, 0, 10));
+ assertNull(actual, "Expected parcReadOnlyBuffer_Wrap to return NULL");
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(buffer);
+ assertTrue(parcReadOnlyBuffer_Position(actual) == 0, "Expected initial position to be 0.");
+ assertTrue(parcReadOnlyBuffer_Limit(actual) == sizeof(array) / sizeof(array[0]), "Expected initial limit to be 10.");
+
+ parcReadOnlyBuffer_Release(&actual);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Wrap_WithOffset)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_Wrap(array, 10, 3, 10);
+
+ PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(buffer);
+ parcBuffer_Release(&buffer);
+ assertTrue(parcReadOnlyBuffer_Capacity(actual) == 10, "Expected initial capacity to be 3.");
+ assertTrue(parcReadOnlyBuffer_Limit(actual) == 10, "Expected initial limit to be 3.");
+ assertTrue(parcReadOnlyBuffer_Position(actual) == 3, "Expected initial position to be 0.");
+
+ parcReadOnlyBuffer_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcReadOnlyBuffer_Allocate_AcquireRelease)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+
+ PARCReadOnlyBuffer *expected = parcReadOnlyBuffer_Create(buffer);
+ PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Acquire(expected);
+
+ assertTrue(expected == actual, "Expected %p, actual %p", (void *) expected, (void *) actual);
+
+ parcReadOnlyBuffer_Release(&expected);
+ assertTrue(expected == NULL, "Expected parcReadOnlyBuffer_Release to NULL the pointer.");
+ parcReadOnlyBuffer_Release(&actual);
+ assertTrue(actual == NULL, "Expected parcReadOnlyBuffer_Release to NULL the pointer.");
+ parcBuffer_Release(&buffer);
+}
+
+//LONGBOW_TEST_CASE_EXPECTS(CreateDestroy, parcReadOnlyBuffer_Allocate_AcquireRelease_TooMany, .event = &LongBowTrapIllegalValue)
+//{
+// PARCBuffer *buffer = parcBuffer_Allocate(10);
+// PARCReadOnlyBuffer *expected = parcReadOnlyBuffer_Create(buffer);
+// PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Acquire(expected);
+// PARCReadOnlyBuffer *alias = actual;
+//
+// parcBuffer_Release(&buffer);
+// parcReadOnlyBuffer_Release(&expected);
+// parcReadOnlyBuffer_Release(&actual);
+// parcReadOnlyBuffer_Release(&alias); // this must fail.
+//}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Array);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_ArrayOffset);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Clear);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Flip);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_GetByte);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_GetArray);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_HasRemaining);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Mark);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Overlay);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Position);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Remaining);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_Rewind);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_SetLimit);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_SetLimit_TruncatePosition);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_SetPosition);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, parcReadOnlyBuffer_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, parcReadOnlyBuffer_Equals)
+{
+ PARCReadOnlyBuffer *x = parcReadOnlyBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+ PARCReadOnlyBuffer *y = parcReadOnlyBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+ PARCReadOnlyBuffer *z = parcReadOnlyBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+ PARCReadOnlyBuffer *u1 = parcReadOnlyBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }, 10, 0, 10);
+ PARCReadOnlyBuffer *u2 = parcReadOnlyBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 9, 0, 9);
+ PARCReadOnlyBuffer *u3 = parcReadOnlyBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9);
+ PARCReadOnlyBuffer *u4 = parcReadOnlyBuffer_SetPosition(parcReadOnlyBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 2);
+ PARCReadOnlyBuffer *u5 = parcReadOnlyBuffer_SetPosition(parcReadOnlyBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 9);
+ PARCReadOnlyBuffer *u6 = parcReadOnlyBuffer_SetPosition(parcReadOnlyBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 9, 0, 9), 9);
+
+ parcObjectTesting_AssertEqualsFunction(parcReadOnlyBuffer_Equals, x, y, z, u1, u2, u3, u4, u5, u6, NULL);
+
+ parcReadOnlyBuffer_Release(&x);
+ parcReadOnlyBuffer_Release(&y);
+ parcReadOnlyBuffer_Release(&z);
+ parcReadOnlyBuffer_Release(&u1);
+ parcReadOnlyBuffer_Release(&u2);
+ parcReadOnlyBuffer_Release(&u3);
+ parcReadOnlyBuffer_Release(&u4);
+ parcReadOnlyBuffer_Release(&u5);
+ parcReadOnlyBuffer_Release(&u6);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Array)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *readWriteBuffer = parcBuffer_Wrap(expected, 10, 0, 10);
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Create(readWriteBuffer);
+ parcBuffer_Release(&readWriteBuffer);
+
+ PARCByteArray *array = parcReadOnlyBuffer_Array(buffer);
+ uint8_t *actual = parcByteArray_Array(array);
+
+ parcReadOnlyBuffer_Release(&buffer);
+
+ assertTrue(expected == actual,
+ "Expected %p, actual %p",
+ (void *) expected, (void *) actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Flip)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_PutArray(parcBuffer_Allocate(10), 10, expected);
+
+ PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(buffer);
+
+ parcReadOnlyBuffer_Flip(actual);
+ assertTrue(parcReadOnlyBuffer_Position(actual) == 0,
+ "Expected position to be 0.");
+ assertTrue(parcReadOnlyBuffer_Limit(actual) == 10,
+ "Expected limit to be 10.");
+
+ parcReadOnlyBuffer_Release(&actual);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Copy)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_PutArray(parcBuffer_Allocate(10), 10, expected);
+
+ PARCReadOnlyBuffer *original = parcReadOnlyBuffer_Create(buffer);
+
+ PARCReadOnlyBuffer *copy = parcReadOnlyBuffer_Copy(original);
+
+ assertTrue(parcReadOnlyBuffer_Equals(original, copy), "Expected the copy to be equal to the original.");
+
+ parcReadOnlyBuffer_Release(&copy);
+ parcReadOnlyBuffer_Release(&original);
+ parcBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Clear)
+{
+ uint8_t expected[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCBuffer *buffer = parcBuffer_PutArray(parcBuffer_Allocate(10), 10, expected);
+
+ PARCReadOnlyBuffer *actual = parcReadOnlyBuffer_Create(buffer);
+ assertTrue(parcReadOnlyBuffer_Position(actual) == 10, "Expected position to be 10.");
+ assertTrue(parcReadOnlyBuffer_Limit(actual) == 10, "Expected limit to be 10.");
+
+ parcReadOnlyBuffer_Clear(actual);
+ assertTrue(parcReadOnlyBuffer_Position(actual) == 0, "Expected position to be 0.");
+ assertTrue(parcReadOnlyBuffer_Limit(actual) == 10, "Expected limit to be 10.");
+
+ parcBuffer_Release(&buffer);
+ parcReadOnlyBuffer_Release(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_ArrayOffset)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ size_t expected = 5;
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, expected, 10);
+
+ size_t actual = parcReadOnlyBuffer_ArrayOffset(buffer);
+ parcReadOnlyBuffer_Release(&buffer);
+
+ assertTrue(0 == actual,
+ "Expected offset to be 0, actual %zu", actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Position)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 5;
+ parcReadOnlyBuffer_SetPosition(buffer, expected);
+
+ size_t actual = parcReadOnlyBuffer_Position(buffer);
+
+ assertTrue(expected == actual,
+ "Expected position to be 0, actual %zu", actual);
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Overlay)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ uint8_t expected[5] = { 5, 6, 7, 8, 9 };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ size_t position = 5;
+ parcReadOnlyBuffer_SetPosition(buffer, position);
+ uint8_t *actual = parcReadOnlyBuffer_Overlay(buffer, sizeof(array) - position);
+
+ assertTrue(memcmp(expected, actual, sizeof(expected)) == 0,
+ "Array contents should not be different.");
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_SetPosition)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 2;
+ parcReadOnlyBuffer_SetPosition(buffer, expected);
+ size_t actual = parcReadOnlyBuffer_Position(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_SetLimit)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 2;
+ parcReadOnlyBuffer_SetLimit(buffer, expected);
+ size_t actual = parcReadOnlyBuffer_Limit(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_SetLimit_TruncatePosition)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ parcReadOnlyBuffer_SetPosition(buffer, 5);
+ parcReadOnlyBuffer_Mark(buffer);
+
+ size_t expected = 2;
+ parcReadOnlyBuffer_SetLimit(buffer, expected);
+ size_t actual = parcReadOnlyBuffer_Limit(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Remaining)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 10;
+ size_t actual = parcReadOnlyBuffer_Remaining(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_HasRemaining)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+ bool actual = parcReadOnlyBuffer_HasRemaining(buffer);
+
+ assertTrue(actual, "Expected true");
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Rewind)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+ parcReadOnlyBuffer_SetPosition(buffer, 4);
+ size_t actual = parcReadOnlyBuffer_Position(buffer);
+ assertTrue(actual == 4, "Expected position to be at 4.");
+
+ parcReadOnlyBuffer_Rewind(buffer);
+
+ actual = parcReadOnlyBuffer_Position(buffer);
+ assertTrue(actual == 0, "Expected position to be at 0.");
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Mark)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ size_t expected = 2;
+ parcReadOnlyBuffer_SetPosition(buffer, expected);
+ parcReadOnlyBuffer_Mark(buffer);
+ parcReadOnlyBuffer_SetPosition(buffer, 4);
+ parcReadOnlyBuffer_Reset(buffer);
+ size_t actual = parcReadOnlyBuffer_Position(buffer);
+
+ assertTrue(expected == actual, "Expected %zd, actual %zd", expected, actual);
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_GetByte)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ uint8_t actual = parcReadOnlyBuffer_GetUint8(buffer);
+
+ assertTrue(array[0] == actual,
+ "Expected %d, actual %d", array[0], actual);
+
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_GetArray)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ uint8_t actual[10];
+
+ parcReadOnlyBuffer_GetArray(buffer, actual, sizeof(actual));
+
+ assertTrue(memcmp(array, actual, sizeof(actual)) == 0,
+ "Expected arrays to be equal.");
+
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_HashCode)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ PARCBuffer *referenceBuffer = parcBuffer_Wrap(array, 10, 0, 10);
+
+ PARCReadOnlyBuffer *buffer1 = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ PARCReadOnlyBuffer *buffer2 = parcReadOnlyBuffer_Wrap(array, 10, 0, 10);
+
+ uint32_t hashX = parcReadOnlyBuffer_HashCode(buffer1);
+ uint32_t hashY = parcReadOnlyBuffer_HashCode(buffer2);
+ uint32_t referenceHash = parcBuffer_HashCode(referenceBuffer);
+
+ assertTrue(hashX == hashY, "Expected %u, actual %u", hashX, hashY);
+ assertTrue(hashX == referenceHash, "Expected %u, actual %u", hashX, hashY);
+
+ parcReadOnlyBuffer_Release(&buffer2);
+ parcReadOnlyBuffer_Release(&buffer1);
+ parcBuffer_Release(&referenceBuffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_ToString)
+{
+ uint8_t array[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 'x' };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, sizeof(array), 0, sizeof(array));
+
+ char *actual = parcReadOnlyBuffer_ToString(buffer);
+
+ assertTrue(strcmp("hello worldx", actual) == 0, "Expected 'hello world', actual %s", actual);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_CASE(Global, parcReadOnlyBuffer_Display)
+{
+ uint8_t array[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 'x' };
+
+ PARCReadOnlyBuffer *buffer = parcReadOnlyBuffer_Wrap(array, sizeof(array), 0, sizeof(array));
+
+ parcReadOnlyBuffer_Display(buffer, 0);
+
+ parcReadOnlyBuffer_Release(&buffer);
+}
+
+LONGBOW_TEST_FIXTURE(Getters)
+{
+ LONGBOW_RUN_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint8);
+ LONGBOW_RUN_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint16);
+ LONGBOW_RUN_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint32);
+ LONGBOW_RUN_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint64);
+ LONGBOW_RUN_TEST_CASE(Getters, parcReadOnlyBuffer_GetAtIndex);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Getters)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(100);
+
+ longBowTestCase_SetClipBoardData(testCase, buffer);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Getters)
+{
+ PARCBuffer *buffer = longBowTestCase_GetClipBoardData(testCase);
+ parcBuffer_Release(&buffer);
+
+ 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(Getters, parcReadOnlyBuffer_GetAtIndex)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint8_t));
+ uint8_t expected = 0x12;
+
+ parcBuffer_PutUint8(buffer, expected);
+ parcBuffer_Flip(buffer);
+
+ PARCReadOnlyBuffer *readOnly = parcReadOnlyBuffer_Create(buffer);
+ uint8_t actual = parcReadOnlyBuffer_GetAtIndex(readOnly, 0);
+
+ parcReadOnlyBuffer_Release(&readOnly);
+ parcBuffer_Release(&buffer);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint8)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint8_t));
+ uint8_t expected = 0x12;
+
+ parcBuffer_PutUint8(buffer, expected);
+ parcBuffer_Flip(buffer);
+
+ PARCReadOnlyBuffer *readOnly = parcReadOnlyBuffer_Create(buffer);
+ uint8_t actual = parcReadOnlyBuffer_GetUint8(readOnly);
+
+ parcReadOnlyBuffer_Release(&readOnly);
+ parcBuffer_Release(&buffer);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint16)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint16_t));
+ uint16_t expected = 0x1234;
+
+ parcBuffer_PutUint16(buffer, expected);
+ parcBuffer_Flip(buffer);
+
+ PARCReadOnlyBuffer *readOnly = parcReadOnlyBuffer_Create(buffer);
+ uint16_t actual = parcReadOnlyBuffer_GetUint16(readOnly);
+
+ parcReadOnlyBuffer_Release(&readOnly);
+ parcBuffer_Release(&buffer);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint32)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint32_t));
+ uint32_t expected = 0x12345678;
+
+ parcBuffer_PutUint32(buffer, expected);
+ parcBuffer_Flip(buffer);
+
+ PARCReadOnlyBuffer *readOnly = parcReadOnlyBuffer_Create(buffer);
+ uint32_t actual = parcReadOnlyBuffer_GetUint32(readOnly);
+
+ parcReadOnlyBuffer_Release(&readOnly);
+ parcBuffer_Release(&buffer);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Getters, parcReadOnlyBuffer_GetUint64)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(uint64_t));
+ uint64_t expected = 0x1234567812345678;
+
+ parcBuffer_PutUint64(buffer, expected);
+ parcBuffer_Flip(buffer);
+
+ PARCReadOnlyBuffer *readOnly = parcReadOnlyBuffer_Create(buffer);
+ uint64_t actual = parcReadOnlyBuffer_GetUint64(readOnly);
+
+ parcReadOnlyBuffer_Release(&readOnly);
+ parcBuffer_Release(&buffer);
+ assertTrue(expected == actual, "Expected %" PRIu64 ", actual %" PRIu64 "", expected, actual);
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, parcReadOnlyBuffer_GetByte_Underflow);
+ LONGBOW_RUN_TEST_CASE(Errors, parcReadOnlyBuffer_Mark_mark_exceeds_position);
+}
+
+typedef struct parc_buffer_longbow_clipboard {
+ PARCReadOnlyBuffer *buffer;
+} parcReadOnlyBuffer_LongBowClipBoard;
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ uint8_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ parcReadOnlyBuffer_LongBowClipBoard *testData = calloc(1, sizeof(parcReadOnlyBuffer_LongBowClipBoard));
+ testData->buffer = parcReadOnlyBuffer_Wrap(array, sizeof(array), 0, sizeof(array));
+
+ longBowTestCase_SetClipBoardData(testCase, testData);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ parcReadOnlyBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ parcReadOnlyBuffer_Release(&testData->buffer);
+ free(testData);
+
+ 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, parcReadOnlyBuffer_GetByte_Underflow, .event = &LongBowTrapOutOfBounds)
+{
+ parcReadOnlyBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ PARCReadOnlyBuffer *buffer = testData->buffer;
+
+ parcReadOnlyBuffer_SetPosition(buffer, 10);
+ parcReadOnlyBuffer_GetUint8(buffer); // this will fail.
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcReadOnlyBuffer_Mark_mark_exceeds_position, .event = &LongBowAssertEvent)
+{
+ parcReadOnlyBuffer_LongBowClipBoard *testData = longBowTestCase_GetClipBoardData(testCase);
+ PARCReadOnlyBuffer *buffer = testData->buffer;
+
+ size_t expected = 2;
+ parcReadOnlyBuffer_SetPosition(buffer, expected);
+ parcReadOnlyBuffer_Mark(buffer);
+ parcReadOnlyBuffer_SetPosition(buffer, 0);
+ parcReadOnlyBuffer_Reset(buffer);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_ReadableBuffer);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_SafeMemory.c b/libparc/parc/algol/test/test_parc_SafeMemory.c
new file mode 100644
index 00000000..53c0b3c8
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_SafeMemory.c
@@ -0,0 +1,813 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_SafeMemory.c"
+
+#include <LongBow/unit-test.h>
+
+#include <fcntl.h>
+
+LONGBOW_TEST_RUNNER(safetyMemory)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(ReportAllocation);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Errors);
+
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(safetyMemory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(safetyMemory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, PARCSafeMemory_Report);
+ LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_StateToString);
+ LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_OK);
+ LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_ALREADYFREE);
+ LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_UNDERRUN);
+ LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_FormatPrefix);
+ LONGBOW_RUN_TEST_CASE(Static, _computeUsableMemoryLength);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Static, PARCSafeMemory_Report)
+{
+ size_t expectedSize = 100;
+ void *memory = parcSafeMemory_Allocate(expectedSize);
+ int fd = open("/dev/null", O_WRONLY);
+ _parcSafeMemory_Report(memory, fd);
+ close(fd);
+ parcSafeMemory_Deallocate(&memory);
+}
+
+LONGBOW_TEST_CASE(Static, _parcSafeMemory_StateToString)
+{
+ assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_OK),
+ "PARCSafeMemoryState_OK cannot be a NULL string.");
+ assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_MISMATCHED),
+ "PARCSafeMemoryState_MISMATCHED cannot be a NULL string.");
+ assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_UNDERRUN),
+ "PARCSafeMemoryState_UNDERRUN cannot be a NULL string.");
+ assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_OVERRUN),
+ "PARCSafeMemoryState_OVERRUN cannot be a NULL string.");
+ assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_NOTHINGALLOCATED),
+ "PARCSafeMemoryState_NOTHINGALLOCATED cannot be a NULL string.");
+ assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_ALREADYFREE),
+ "PARCSafeMemoryState_ALREADYFREE cannot be a NULL string.");
+ assertNotNull(_parcSafeMemory_StateToString(-1),
+ "Garbage cannot be represented by a NULL string.");
+}
+
+LONGBOW_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_OK)
+{
+ size_t expectedLength = 5;
+ int expectedAlignment = sizeof(void *);
+ char origin[100]; // just some number
+
+ void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) origin, expectedLength, expectedAlignment);
+ PARCSafeMemoryState actual = _parcSafeMemory_GetPrefixState(memory);
+ assertTrue(actual == PARCSafeMemoryState_OK,
+ "Expected PARCSafeMemoryState_OK, actual = %d", actual);
+}
+
+LONGBOW_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_ALREADYFREE)
+{
+ PARCSafeMemoryUsable *usable = parcSafeMemory_Allocate(10);
+ PARCSafeMemoryUsable *saved = usable;
+
+ parcSafeMemory_Deallocate((void **) &usable);
+
+ PARCSafeMemoryState actual = _parcSafeMemory_GetPrefixState(saved);
+ assertTrue(actual == PARCSafeMemoryState_ALREADYFREE,
+ "Expected PARCSafeMemoryState_ALREADYFREE, actual = %d", actual);
+}
+
+LONGBOW_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_UNDERRUN)
+{
+ char *usable = parcSafeMemory_Allocate(10);
+
+ char savedByte = usable[-1];
+ usable[-1] = 0;
+
+ PARCSafeMemoryState actual = _parcSafeMemory_GetPrefixState((PARCSafeMemoryUsable *) usable);
+ assertTrue(actual == PARCSafeMemoryState_UNDERRUN,
+ "Expected PARCSafeMemoryState_UNDERRUN, actual = %d", actual);
+ usable[-1] = savedByte;
+ parcSafeMemory_Deallocate((void **) &usable);
+}
+
+LONGBOW_TEST_CASE(Static, _parcSafeMemory_FormatPrefix)
+{
+ size_t expectedLength = 5;
+ int expectedAlignment = sizeof(void *) - 1;
+ char base[100]; // just some number
+ void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment);
+
+ assertNull(memory,
+ "Expected _parcSafeMemory_FormatPrefix to return NULL for bad alignment specification.");
+}
+
+LONGBOW_TEST_CASE(Static, _computeUsableMemoryLength)
+{
+ size_t actual = _computeUsableMemoryLength(100, sizeof(void *));
+
+ // The result must be >= to the requested length and an even multiple of sizeof(void *)
+ assertTrue(actual >= 100 && (actual % sizeof(void *)) == 0,
+ "Expected the result to be >= to the requested length and an even multiple of sizeof(void *)");
+}
+
+LONGBOW_TEST_FIXTURE(ReportAllocation)
+{
+ LONGBOW_RUN_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_Empty);
+ LONGBOW_RUN_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_One);
+ LONGBOW_RUN_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_Deallocated);
+}
+
+LONGBOW_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_Empty)
+{
+ _parcSafeMemory_DeallocateAll();
+ int fd = open("/dev/null", O_WRONLY);
+ size_t result = parcSafeMemory_ReportAllocation(fd);
+ close(fd);
+ assertTrue(result == 0, "Expected 0, was %zd", result);
+}
+
+LONGBOW_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_One)
+{
+ void *memory;
+ size_t size = 100;
+
+ memory = parcSafeMemory_Allocate(size);
+
+ int fd = open("/dev/null", O_WRONLY);
+ size_t result = parcSafeMemory_ReportAllocation(fd);
+ close(fd);
+ assertTrue(result == 1, "Expected 1, was %zd", result);
+
+ parcSafeMemory_Deallocate(&memory);
+}
+
+LONGBOW_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_Deallocated)
+{
+ size_t size = 100;
+ void *memory = parcSafeMemory_Allocate(size);
+ assertTrue(parcSafeMemory_Outstanding() != 0, "No memory allocated!");
+ PARCSafeMemoryState state = _parcSafeMemory_GetState(memory);
+ parcSafeMemory_Deallocate(&memory);
+ assertTrue(state == PARCSafeMemoryState_OK, "Expected uncorrupted memory.");
+
+ int fd = open("/dev/null", O_WRONLY);
+ size_t result = parcSafeMemory_ReportAllocation(fd);
+ close(fd);
+
+ assertTrue(result == 0, "Expected 0, was %zd", result);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(ReportAllocation)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(ReportAllocation)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Allocate);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_MemAlign);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARCSafeMemory_Realloc_Larger);
+ LONGBOW_RUN_TEST_CASE(Global, PARCSafeMemory_Realloc_Smaller);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Reallocate_Zero);
+ LONGBOW_RUN_TEST_CASE(Global, PARCSafeMemory_Validate);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Allocate_BadAlignment);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Allocate_BadSize);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_AllocateAndClear);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Reallocate);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Deallocate_NothingAllocated);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_IsValid_True);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_IsValid_False);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Display_NULL);
+
+ LONGBOW_RUN_TEST_CASE(Global, compute_prefix_length);
+ LONGBOW_RUN_TEST_CASE(Global, _parcSafeMemory_FormatMemory);
+ LONGBOW_RUN_TEST_CASE(Global, memory_prefix_format);
+ LONGBOW_RUN_TEST_CASE(Global, memory_prefix_validate);
+ LONGBOW_RUN_TEST_CASE(Global, memory_suffix_format);
+ LONGBOW_RUN_TEST_CASE(Global, memory_suffix_validate);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_StringDuplicate);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_StringDuplicate_Long);
+ LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_StringDuplicate_Short);
+ LONGBOW_RUN_TEST_CASE(Global, validateAlignment);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ assertTrue(parcSafeMemory_Outstanding() == 0, "Expected 0 outstanding allocations")
+ {
+ printf("Leaking test case: %s", longBowTestCase_GetName(testCase));
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+LONGBOW_TEST_CASE(Global, validateAlignment)
+{
+ assertTrue(_alignmentIsValid(sizeof(void *)),
+ "Expected alignment of sizeof(void *) failed.");
+ assertTrue(_alignmentIsValid(16),
+ "Expected alignment of 16 failed.");
+}
+
+LONGBOW_TEST_CASE(Global, compute_prefix_length)
+{
+ // Test that the result is a multiple of the alignment value and greater than the size of _MemoryPrefix.
+ for (int i = 0; i < 9; i++) {
+ size_t alignment = 1 << i;
+ size_t actual = _computePrefixLength(alignment);
+ assertTrue((actual & (alignment - 1)) == 0,
+ "Alignment needs to be a multiple of %zd", alignment);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, memory_prefix_format)
+{
+ size_t expectedLength = 5;
+ int expectedAlignment = sizeof(void *);
+ char base[100];
+ void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment);
+
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(memory);
+
+ assertAligned(prefix, sizeof(void *),
+ "prefix address %p is not aligned to %d",
+ memory, expectedAlignment);
+ assertAligned(memory, expectedAlignment,
+ "memory address %p is not aligned to %d",
+ memory, expectedAlignment);
+
+ assertTrue((void *) prefix >= (void *) base,
+ "Expected >= %p, actual %p", (void *) base, (void *) prefix);
+ assertTrue(_parcSafeMemory_PrefixMagic == prefix->magic,
+ "Prefix magic is wrong.");
+ assertTrue(expectedLength == prefix->requestedLength,
+ "Expected length %zd, actual %zd", expectedLength, prefix->requestedLength);
+ assertTrue(expectedAlignment == prefix->alignment,
+ "Expected alignment %d, actual %zu",
+ expectedAlignment, prefix->alignment);
+ assertTrue(_parcSafeMemory_Guard == prefix->guard,
+ "Prefix guard is wrong.");
+}
+
+LONGBOW_TEST_CASE(Global, memory_suffix_format)
+{
+ size_t expectedLength = 5;
+ int expectedAlignment = sizeof(void *);
+ char base[100];
+ void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment);
+
+ _MemorySuffix *suffix = _parcSafeMemory_FormatSuffix(memory);
+ assertAligned(suffix, sizeof(void *), "suffix pointer is not aligned to %zu", sizeof(void*));
+}
+
+LONGBOW_TEST_CASE(Global, memory_suffix_validate)
+{
+ size_t expectedLength = 5;
+ int expectedAlignment = sizeof(void *);
+ char base[100];
+ void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment);
+
+ _MemorySuffix *suffix = _parcSafeMemory_FormatSuffix(memory);
+ assertAligned(suffix, sizeof(void *),
+ "suffix pointer is not aligned to %zu", sizeof(void*));
+
+ PARCSafeMemoryState suffixState = _parcSafeMemory_GetSuffixState(memory);
+ assertTrue(suffixState == PARCSafeMemoryState_OK,
+ "Expected PARCSafeMemoryState_OK suffix state, actual %s", _parcSafeMemory_StateToString(suffixState));
+}
+
+LONGBOW_TEST_CASE(Global, memory_prefix_validate)
+{
+ size_t expectedLength = 5;
+ int expectedAlignment = sizeof(void *);
+ char base[100];
+
+ void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment);
+ PARCSafeMemoryState actual = _parcSafeMemory_GetPrefixState(memory);
+ assertTrue(actual == PARCSafeMemoryState_OK,
+ "Expected valid prefix, actual = %d", actual);
+}
+
+LONGBOW_TEST_CASE(Global, _parcSafeMemory_FormatMemory)
+{
+ size_t expectedLength = 5;
+ int expectedAlignment = sizeof(void *);
+ char base[100];
+
+ void *memory = _parcSafeMemory_FormatMemory((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment);
+
+ PARCSafeMemoryState state = _parcSafeMemory_GetState(memory);
+
+ assertTrue(state == PARCSafeMemoryState_OK,
+ "Memory did not validate. Actual %d", state);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_Allocate)
+{
+ void *memory;
+ size_t size = 100;
+
+ memory = parcSafeMemory_Allocate(size);
+
+ assertTrue(memory != NULL,
+ "Expected non-NULL return.");
+
+ assertTrue((_parcSafeMemory_GetPrefixState(memory)) == PARCSafeMemoryState_OK,
+ "Prefix did not validate.");
+ parcSafeMemory_Deallocate(&memory);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_MemAlign)
+{
+ void *memory;
+ size_t size = 100;
+
+ int failure = parcSafeMemory_MemAlign(&memory, sizeof(void *), size);
+ assertTrue(failure == 0,
+ "parcSafeMemory_MemAlign failed: %d", failure);
+
+ assertTrue(memory != NULL,
+ "Expected non-NULL return.");
+
+ assertTrue((_parcSafeMemory_GetPrefixState(memory)) == PARCSafeMemoryState_OK,
+ "Prefix did not validate.");
+ parcSafeMemory_Deallocate(&memory);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_ReportAllocation)
+{
+ void *memory;
+ size_t size = 100;
+
+ memory = parcSafeMemory_Allocate(size);
+ assertTrue(memory != NULL, "Expected non-NULL return.");
+ PARCSafeMemoryState prefixState = _parcSafeMemory_GetPrefixState(memory);
+ assertTrue(prefixState == PARCSafeMemoryState_OK,
+ "Prefix did not validate.");
+
+ parcSafeMemory_ReportAllocation(1);
+}
+
+LONGBOW_TEST_CASE(Global, PARCSafeMemory_Validate)
+{
+ void *memory;
+ size_t size = 100;
+
+ memory = parcSafeMemory_Allocate(size);
+
+ assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK,
+ "Memory did not validate.");
+ parcSafeMemory_Deallocate(&memory);
+}
+
+LONGBOW_TEST_CASE(Global, PARCSafeMemory_Realloc_Larger)
+{
+ void *memory = parcSafeMemory_Allocate(100);
+
+ for (unsigned char i = 0; i < 100; i++) {
+ ((unsigned char *) memory)[i] = i;
+ }
+
+ assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK,
+ "Expected memory to be OK.");
+
+ size_t expectedLength = 100 + 1;
+ unsigned char *newMemory = parcSafeMemory_Reallocate(memory, expectedLength);
+
+ assertTrue(_parcSafeMemory_GetState((PARCSafeMemoryUsable *) memory) != PARCSafeMemoryState_OK,
+ "Expected original memory to NOT be OK.");
+ assertTrue(_parcSafeMemory_GetState((PARCSafeMemoryUsable *) newMemory) == PARCSafeMemoryState_OK,
+ "Expected new memory to be OK.");
+
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix((PARCSafeMemoryUsable *) newMemory);
+ assertTrue(prefix->requestedLength == expectedLength,
+ "Prefix Expected length %zd, actual %zd", expectedLength, prefix->requestedLength);
+
+ for (int i = 0; i < 100; i++) {
+ assertTrue(((unsigned char *) newMemory)[i] == i,
+ "PARCSafeMemory_Realloc did not copy old memory correctly");
+ }
+
+ assertTrue(parcSafeMemory_Outstanding() != 0,
+ "No memory allocated!");
+ PARCSafeMemoryState state = _parcSafeMemory_GetState((PARCSafeMemoryUsable *) newMemory);
+ parcSafeMemory_Deallocate((void **) &newMemory);
+ assertTrue(state == PARCSafeMemoryState_OK,
+ "Expected PARCSafeMemory_Deallocate of new memory to be OK, actual =%d", state);
+ assertTrue(_parcSafeMemory_GetState(memory) != PARCSafeMemoryState_OK,
+ "Expected old memory to be invalid.");
+}
+
+LONGBOW_TEST_CASE(Global, PARCSafeMemory_Realloc_Smaller)
+{
+ void *memory = parcSafeMemory_Allocate(100);
+ assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK,
+ "Memory did not validate.");
+
+ for (unsigned char i = 0; i < 100; i++) {
+ ((unsigned char *) memory)[i] = i;
+ }
+
+ size_t expectedLength = 100 - 1;
+ unsigned char *newMemory = parcSafeMemory_Reallocate(memory, expectedLength);
+
+ assertTrue(_parcSafeMemory_GetState(memory) != PARCSafeMemoryState_OK,
+ "Expected original memory to NOT be OK.");
+ assertTrue(_parcSafeMemory_GetState((PARCSafeMemoryUsable *) newMemory) == PARCSafeMemoryState_OK,
+ "Expected new memory to be OK.");
+
+ _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix((PARCSafeMemoryUsable *) newMemory);
+ assertTrue(prefix->requestedLength == expectedLength,
+ "Prefix Expected length %zd, actual %zd", expectedLength, prefix->requestedLength);
+
+ for (int i = 0; i < expectedLength; i++) {
+ assertTrue(((unsigned char *) newMemory)[i] == i,
+ "PARCSafeMemory_Realloc did not copy correctly");
+ }
+
+ assertTrue(parcSafeMemory_Outstanding() != 0,
+ "No memory allocated!");
+ PARCSafeMemoryState state = _parcSafeMemory_GetState((PARCSafeMemoryUsable *) newMemory);
+ parcSafeMemory_Deallocate((void **) &newMemory);
+ assertTrue(state == PARCSafeMemoryState_OK,
+ "Expected PARCSafeMemory_Deallocate of new memory to be OK, actual =%d", state);
+ assertTrue(_parcSafeMemory_GetState(memory) != PARCSafeMemoryState_OK,
+ "Expected old memory to be invalid.");
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_Reallocate_Zero)
+{
+ void *memory = parcSafeMemory_Allocate(100);
+ assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK,
+ "Memory did not validate.");
+
+ for (unsigned char i = 0; i < 100; i++) {
+ ((unsigned char *) memory)[i] = i;
+ }
+
+ size_t expectedLength = 0;
+ unsigned char *newMemory = parcSafeMemory_Reallocate(memory, expectedLength);
+
+ assertTrue(newMemory == NULL,
+ "Expected NULL, actual %p", (void *) newMemory);
+
+ parcSafeMemory_Deallocate(&memory);
+ assertNull(memory,
+ "Expected memory pointer to be NULL.");
+}
+
+LONGBOW_TEST_CASE(Global, PARCSafeMemory_DoubleFree)
+{
+ size_t expectedSize = 100;
+
+ void *memory = parcSafeMemory_Allocate(expectedSize);
+ assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK,
+ "Memory did not validate.");
+
+ for (unsigned char i = 0; i < expectedSize; i++) {
+ ((unsigned char *) memory)[i] = i;
+ }
+
+ assertTrue(parcSafeMemory_Outstanding() != 0,
+ "No memory allocated!");
+ PARCSafeMemoryState state = _parcSafeMemory_GetState(memory);
+ parcSafeMemory_Deallocate(&memory);
+ assertTrue(state == PARCSafeMemoryState_OK,
+ "Expected memory to validate");
+ assertTrue(parcSafeMemory_Outstanding() != 0,
+ "No memory allocated!");
+ state = _parcSafeMemory_GetState(memory);
+ parcSafeMemory_Deallocate(&memory);
+ assertTrue(state == PARCSafeMemoryState_UNDERRUN,
+ "Expected memory to be underrun (double free).");
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_StringDuplicate)
+{
+ char *string = "hello world";
+ char *actual = parcSafeMemory_StringDuplicate(string, strlen(string));
+
+ assertTrue(strcmp(string, actual) == 0,
+ "Expected %s, actual %s", string, actual);
+ parcSafeMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_StringDuplicate_Long)
+{
+ char *string = "hello world";
+ char *actual = parcSafeMemory_StringDuplicate(string, SIZE_MAX);
+
+ assertTrue(strcmp(string, actual) == 0,
+ "Expected %s, actual %s", string, actual);
+ parcSafeMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_StringDuplicate_Short)
+{
+ char *string = "hello world";
+ char *expected = "hello";
+ char *actual = parcSafeMemory_StringDuplicate(string, 5);
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected %s, actual %s", expected, actual);
+ parcSafeMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_Allocate_BadAlignment)
+{
+ void *result;
+ size_t alignment = 3;
+ size_t size = 100;
+
+ int failure = parcSafeMemory_MemAlign(&result, alignment, size);
+ assertTrue(failure == EINVAL,
+ "parcSafeMemory_MemAlign failed to report bad aligment specification");
+ assertTrue(parcSafeMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocations, actual %d", parcSafeMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_Allocate_BadSize)
+{
+ void *result;
+ size_t alignment = sizeof(void *);
+ size_t size = 0;
+
+ int failure = parcSafeMemory_MemAlign(&result, alignment, size);
+ assertTrue(failure == EINVAL,
+ "parcSafeMemory_MemAlign failed to report bad aligment specification");
+ assertTrue(parcSafeMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocation, actual %d", parcSafeMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_AllocateAndClear)
+{
+ void *result;
+ size_t size = 100;
+
+ result = parcSafeMemory_AllocateAndClear(size);
+ assertNotNull(result,
+ "parcSafeMemory_AllocateAndClear failed: NULL result.");
+
+ for (size_t i = 0; i < size; i++) {
+ assertTrue(((char *) result)[i] == 0,
+ "parcSafeMemory_AllocateAndClear failed to zero memory at index %zd", i);
+ }
+ assertTrue(parcSafeMemory_Outstanding() == 1,
+ "Expected 1 outstanding allocation, actual %d", parcSafeMemory_Outstanding());
+ parcSafeMemory_Deallocate(&result);
+ assertTrue(parcSafeMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocation, actual %d", parcSafeMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_Reallocate)
+{
+ size_t size = 100;
+
+ void *result = parcSafeMemory_AllocateAndClear(size);
+ assertNotNull(result,
+ "parcSafeMemory_Allocate failed: NULL.");
+
+ for (size_t i = 0; i < size; i++) {
+ assertTrue(((char *) result)[i] == 0,
+ "parcSafeMemory_AllocateAndClear failed to zero memory at index %zd", i);
+ }
+
+ result = parcSafeMemory_Reallocate(result, size * 2);
+
+ assertTrue(parcSafeMemory_Outstanding() == 1,
+ "Expected 1 outstanding allocation, actual %d", parcSafeMemory_Outstanding());
+ parcSafeMemory_Deallocate(&result);
+ assertTrue(parcSafeMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocations, actual %d", parcSafeMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_Deallocate_NothingAllocated)
+{
+ void *result = 0;
+
+ parcSafeMemory_Deallocate(&result);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_IsValid_True)
+{
+ void *result = parcSafeMemory_AllocateAndClear(5);
+
+ assertTrue(parcSafeMemory_IsValid(result), "Expected properly allocated memory to be valid PARC Safe Memory.");
+
+ parcSafeMemory_Deallocate(&result);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_IsValid_False)
+{
+ char *memory[10];
+
+ assertFalse(parcSafeMemory_IsValid(memory), "Expected improperly allocated memory to be invalid PARC Safe Memory.");
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_Display)
+{
+ void *result = parcSafeMemory_AllocateAndClear(5);
+
+ parcSafeMemory_Display(result, 0);
+ parcSafeMemory_Deallocate(&result);
+}
+
+LONGBOW_TEST_CASE(Global, parcSafeMemory_Display_NULL)
+{
+ parcSafeMemory_Display(NULL, 0);
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, parcSafeMemory_Reallocate_NULL);
+ LONGBOW_RUN_TEST_CASE(Errors, PARCSafeMemory_Deallocate_Overrun);
+ LONGBOW_RUN_TEST_CASE(Errors, PARCSafeMemory_Deallocate_Underrun);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ // The tests purposefully wreck the various per-allocation accounting structures for the allocated memory in order to test for
+ // properly catching the overrun, underrun or other damage.
+ // As a result any cleanup of allocated memory is not possible, so these tests leak allocated memory.
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Errors, parcSafeMemory_Reallocate_NULL)
+{
+ void *result = NULL;
+ size_t size = 100;
+
+ result = parcSafeMemory_Reallocate(result, size * 2);
+
+ assertTrue(parcSafeMemory_Outstanding() == 1,
+ "Expected 1 outstanding allocation, actual %d", parcSafeMemory_Outstanding());
+ parcSafeMemory_Deallocate(&result);
+ assertTrue(parcSafeMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocations, actual %d", parcSafeMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, PARCSafeMemory_Deallocate_Underrun, .event = &LongBowTrapUnexpectedStateEvent)
+{
+ size_t expectedSize = sizeof(void *) * 2;
+ void *memory = parcSafeMemory_Allocate(expectedSize);
+ assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK,
+ "Memory did not validate.");
+
+ for (int i = -2; i < (int) expectedSize; i++) {
+ ((unsigned char *) memory)[i] = (unsigned char) i;
+ }
+
+ assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_UNDERRUN,
+ "Memory did not underrun.");
+
+ assertTrue(parcSafeMemory_Outstanding() != 0,
+ "No memory allocated!");
+ PARCSafeMemoryState state = _parcSafeMemory_GetState(memory);
+ parcSafeMemory_Deallocate(&memory);
+
+ assertTrue(state == PARCSafeMemoryState_UNDERRUN,
+ "Expected memory to be underrun");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, PARCSafeMemory_Deallocate_Overrun, .event = &LongBowTrapUnexpectedStateEvent)
+{
+ size_t expectedSize = 100;
+ void *memory = parcSafeMemory_Allocate(expectedSize);
+ assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK,
+ "Memory did not validate.");
+
+ for (unsigned char i = 0; i < expectedSize + 5; i++) {
+ ((unsigned char *) memory)[i] = i;
+ }
+
+ assertTrue(parcSafeMemory_Outstanding() != 0,
+ "No memory allocated!");
+ assertTrue(_parcSafeMemory_GetState(memory) != PARCSafeMemoryState_OK,
+ "Expected not OK, actual %s", _parcSafeMemory_StateToString(_parcSafeMemory_GetState(memory)));
+ // this is expected to fail
+ parcSafeMemory_Deallocate(&memory);
+}
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcSafeMemory_AllocateDeallocate_1000000_WorstCase);
+ LONGBOW_RUN_TEST_CASE(Performance, parcSafeMemory_AllocateDeallocate_1000000_BestCase);
+
+ LONGBOW_RUN_TEST_CASE(Performance, _computeUsableMemoryLength);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+void *memory[1000000];
+
+LONGBOW_TEST_CASE(Performance, parcSafeMemory_AllocateDeallocate_1000000_WorstCase)
+{
+ size_t size = 100;
+
+ for (int i = 0; i < sizeof(memory) / sizeof(memory[0]); i++) {
+ memory[i] = parcSafeMemory_Allocate(size);
+ }
+ for (int i = 0; i < sizeof(memory) / sizeof(memory[0]); i++) {
+ parcSafeMemory_Deallocate(&memory[i]);
+ }
+}
+
+LONGBOW_TEST_CASE(Performance, parcSafeMemory_AllocateDeallocate_1000000_BestCase)
+{
+ size_t size = 100;
+
+ for (int i = 0; i < sizeof(memory) / sizeof(memory[0]); i++) {
+ memory[i] = parcSafeMemory_Allocate(size);
+ }
+
+ int i = sizeof(memory) / sizeof(memory[0]);
+ do {
+ i--;
+ parcSafeMemory_Deallocate(&memory[i]);
+ } while (i > 0);
+}
+
+LONGBOW_TEST_CASE(Performance, _computeUsableMemoryLength)
+{
+ for (int i = 0; i < 100000000; i++) {
+ size_t alignment = sizeof(void *);
+ size_t requestedLength = 10;
+ _computeUsableMemoryLength(requestedLength, alignment);
+ }
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(safetyMemory);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_SortedList.c b/libparc/parc/algol/test/test_parc_SortedList.c
new file mode 100644
index 00000000..f0445d86
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_SortedList.c
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_SortedList.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(parc_SortedList)
+{
+ // 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);
+ LONGBOW_RUN_TEST_FIXTURE(Specialization);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_SortedList)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_SortedList)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateCompare);
+}
+
+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)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ assertNotNull(instance, "Expected non-null result from parcSortedList_Create();");
+
+ parcObjectTesting_AssertAcquire(instance);
+
+ parcSortedList_Release(&instance);
+ assertNull(instance, "Expected null result from parcSortedList_Release();");
+}
+
+// A signum function to compare two PARCBuffers by length of buffer.
+static int
+_compareTwoBuffersByLength(const PARCObject *buf1, const PARCObject *buf2)
+{
+ size_t size1 = parcBuffer_Limit((PARCBuffer *) buf1);
+ size_t size2 = parcBuffer_Limit((PARCBuffer *) buf2);
+
+ if (size1 > size2) {
+ return 1;
+ } else if (size2 > size1) {
+ return -1;
+ }
+ return 0;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateCompare)
+{
+ PARCSortedList *instance = parcSortedList_CreateCompare(_compareTwoBuffersByLength);
+
+ PARCBuffer *buf1 = parcBuffer_WrapCString("medium long");
+ PARCBuffer *buf2 = parcBuffer_WrapCString("somewhat longer");
+ PARCBuffer *buf3 = parcBuffer_WrapCString("short");
+
+ parcSortedList_Add(instance, buf1);
+ parcSortedList_Add(instance, buf2);
+ parcSortedList_Add(instance, buf3);
+
+ PARCBuffer *test = parcSortedList_GetAtIndex(instance, 0);
+ assertTrue(test == buf3, "Expected the shortes buffer first");
+
+ test = parcSortedList_GetAtIndex(instance, 1);
+ assertTrue(test == buf1, "Expected the medium length buffer second");
+
+ test = parcSortedList_GetAtIndex(instance, 2);
+ assertTrue(test == buf2, "Expected the longest buffer last");
+
+ parcBuffer_Release(&buf1);
+ parcBuffer_Release(&buf2);
+ parcBuffer_Release(&buf3);
+
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcSortedList_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcSortedList_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcSortedList_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcSortedList_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcSortedList_IsValid);
+ LONGBOW_RUN_TEST_CASE(Global, parcSortedList_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Global, parcSortedList_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, parcSortedList_Copy)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ PARCSortedList *copy = parcSortedList_Copy(instance);
+ assertTrue(parcSortedList_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcSortedList_Release(&instance);
+ parcSortedList_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, parcSortedList_Display)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcSortedList_Equals)
+{
+ PARCSortedList *x = parcSortedList_Create();
+ PARCSortedList *y = parcSortedList_Create();
+ PARCSortedList *z = parcSortedList_Create();
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcSortedList_Release(&x);
+ parcSortedList_Release(&y);
+ parcSortedList_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Global, parcSortedList_HashCode)
+{
+ PARCSortedList *x = parcSortedList_Create();
+ PARCSortedList *y = parcSortedList_Create();
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcSortedList_Release(&x);
+ parcSortedList_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Global, parcSortedList_IsValid)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ assertTrue(parcSortedList_IsValid(instance), "Expected parcSortedList_Create to result in a valid instance.");
+
+ parcSortedList_Release(&instance);
+ assertFalse(parcSortedList_IsValid(instance), "Expected parcSortedList_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcSortedList_ToJSON)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+
+ PARCJSON *json = parcSortedList_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcSortedList_ToString)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+
+ char *string = parcSortedList_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcSortedList_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_Add);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_Remove);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_GetAtIndex);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_GetFirst);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_GetLast);
+
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_RemoveFirst);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_RemoveFirst_SingleElement);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSortedList_RemoveLast);
+}
+
+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;
+}
+
+static void
+dump(PARCSortedList *i)
+{
+ PARCIterator *iterator = parcSortedList_CreateIterator(i);
+ while (parcIterator_HasNext(iterator)) {
+ PARCBuffer *buffer = parcIterator_Next(iterator);
+ parcBuffer_Display(buffer, 0);
+ }
+
+ parcIterator_Release(&iterator);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_Add)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ PARCBuffer *element1 = parcBuffer_WrapCString("1");
+ PARCBuffer *element2 = parcBuffer_WrapCString("2");
+ PARCBuffer *element3 = parcBuffer_WrapCString("3");
+ PARCBuffer *element4 = parcBuffer_WrapCString("4");
+ PARCBuffer *element7 = parcBuffer_WrapCString("7");
+ PARCBuffer *element6 = parcBuffer_WrapCString("6");
+ PARCBuffer *element5 = parcBuffer_WrapCString("5");
+ PARCBuffer *element8 = parcBuffer_WrapCString("8");
+
+ parcSortedList_Add(instance, element2);
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Add(instance, element8);
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Add(instance, element3);
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Add(instance, element4);
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Add(instance, element7);
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Add(instance, element6);
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Add(instance, element5);
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Add(instance, element1);
+ parcSortedList_Display(instance, 0);
+ parcSortedList_Add(instance, element6);
+ parcSortedList_Display(instance, 0);
+
+ dump(instance);
+
+ parcBuffer_Release(&element1);
+ parcBuffer_Release(&element2);
+ parcBuffer_Release(&element3);
+ parcBuffer_Release(&element4);
+ parcBuffer_Release(&element5);
+ parcBuffer_Release(&element6);
+ parcBuffer_Release(&element7);
+ parcBuffer_Release(&element8);
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_Remove)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ PARCBuffer *element1 = parcBuffer_WrapCString("1");
+ PARCBuffer *element2 = parcBuffer_WrapCString("2");
+ PARCBuffer *element3 = parcBuffer_WrapCString("3");
+ PARCBuffer *element4 = parcBuffer_WrapCString("4");
+ PARCBuffer *element7 = parcBuffer_WrapCString("7");
+ PARCBuffer *element6 = parcBuffer_WrapCString("6");
+ PARCBuffer *element5 = parcBuffer_WrapCString("5");
+ PARCBuffer *element8 = parcBuffer_WrapCString("8");
+
+ parcSortedList_Add(instance, element1);
+ parcSortedList_Add(instance, element2);
+ parcSortedList_Add(instance, element3);
+ parcSortedList_Display(instance, 0);
+
+ parcSortedList_Remove(instance, element2);
+
+ assertTrue(parcSortedList_Size(instance) == 2, "Expected list to be 2 in size");
+
+ parcBuffer_Release(&element1);
+ parcBuffer_Release(&element2);
+ parcBuffer_Release(&element3);
+ parcBuffer_Release(&element4);
+ parcBuffer_Release(&element5);
+ parcBuffer_Release(&element6);
+ parcBuffer_Release(&element7);
+ parcBuffer_Release(&element8);
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_GetAtIndex)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ PARCBuffer *element1 = parcBuffer_WrapCString("1");
+ PARCBuffer *element2 = parcBuffer_WrapCString("2");
+ PARCBuffer *element3 = parcBuffer_WrapCString("3");
+ PARCBuffer *element4 = parcBuffer_WrapCString("4");
+ PARCBuffer *element7 = parcBuffer_WrapCString("7");
+ PARCBuffer *element6 = parcBuffer_WrapCString("6");
+ PARCBuffer *element5 = parcBuffer_WrapCString("5");
+ PARCBuffer *element8 = parcBuffer_WrapCString("8");
+
+ parcSortedList_Add(instance, element1);
+ parcSortedList_Add(instance, element2);
+ parcSortedList_Add(instance, element3);
+
+ PARCBuffer *actual = (PARCBuffer *) parcSortedList_GetAtIndex(instance, 1);
+ assertTrue(parcBuffer_Equals(element2, actual), "Got the wrong value at index 1");
+
+ parcBuffer_Release(&element1);
+ parcBuffer_Release(&element2);
+ parcBuffer_Release(&element3);
+ parcBuffer_Release(&element4);
+ parcBuffer_Release(&element5);
+ parcBuffer_Release(&element6);
+ parcBuffer_Release(&element7);
+ parcBuffer_Release(&element8);
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_GetFirst)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ PARCBuffer *element1 = parcBuffer_WrapCString("1");
+ PARCBuffer *element2 = parcBuffer_WrapCString("2");
+ PARCBuffer *element3 = parcBuffer_WrapCString("3");
+ PARCBuffer *element4 = parcBuffer_WrapCString("4");
+ PARCBuffer *element7 = parcBuffer_WrapCString("7");
+ PARCBuffer *element6 = parcBuffer_WrapCString("6");
+ PARCBuffer *element5 = parcBuffer_WrapCString("5");
+ PARCBuffer *element8 = parcBuffer_WrapCString("8");
+
+ parcSortedList_Add(instance, element1);
+ parcSortedList_Add(instance, element2);
+ parcSortedList_Add(instance, element3);
+
+ PARCBuffer *actual = (PARCBuffer *) parcSortedList_GetFirst(instance);
+ assertTrue(parcBuffer_Equals(element1, actual), "Got the wrong value.");
+
+ parcBuffer_Release(&element1);
+ parcBuffer_Release(&element2);
+ parcBuffer_Release(&element3);
+ parcBuffer_Release(&element4);
+ parcBuffer_Release(&element5);
+ parcBuffer_Release(&element6);
+ parcBuffer_Release(&element7);
+ parcBuffer_Release(&element8);
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_GetLast)
+{
+ PARCSortedList *instance = parcSortedList_Create();
+ PARCBuffer *element1 = parcBuffer_WrapCString("1");
+ PARCBuffer *element2 = parcBuffer_WrapCString("2");
+ PARCBuffer *element3 = parcBuffer_WrapCString("3");
+ PARCBuffer *element4 = parcBuffer_WrapCString("4");
+ PARCBuffer *element7 = parcBuffer_WrapCString("7");
+ PARCBuffer *element6 = parcBuffer_WrapCString("6");
+ PARCBuffer *element5 = parcBuffer_WrapCString("5");
+ PARCBuffer *element8 = parcBuffer_WrapCString("8");
+
+ parcSortedList_Add(instance, element1);
+ parcSortedList_Add(instance, element2);
+ parcSortedList_Add(instance, element3);
+
+ PARCBuffer *actual = (PARCBuffer *) parcSortedList_GetLast(instance);
+ assertTrue(parcBuffer_Equals(element3, actual), "Got the wrong value at index 1");
+
+ parcBuffer_Release(&element1);
+ parcBuffer_Release(&element2);
+ parcBuffer_Release(&element3);
+ parcBuffer_Release(&element4);
+ parcBuffer_Release(&element5);
+ parcBuffer_Release(&element6);
+ parcBuffer_Release(&element7);
+ parcBuffer_Release(&element8);
+ parcSortedList_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_RemoveFirst)
+{
+ PARCSortedList *deque = parcSortedList_Create();
+
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ parcSortedList_Add(deque, object1);
+ parcSortedList_Add(deque, object2);
+ parcSortedList_Add(deque, object3);
+
+ PARCBuffer *peek = parcSortedList_RemoveFirst(deque);
+ assertTrue(parcBuffer_Equals(object1, peek), "Objects out of order");
+
+ parcBuffer_Release(&peek);
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcSortedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_RemoveFirst_SingleElement)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCSortedList *deque = parcSortedList_Create();
+ parcSortedList_Add(deque, object1);
+
+ PARCBuffer *peek = parcSortedList_RemoveFirst(deque);
+ assertTrue(parcBuffer_Equals(object1, peek),
+ "Objects out of order.");
+
+ parcBuffer_Release(&peek);
+ parcBuffer_Release(&object1);
+ parcSortedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_RemoveLast)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+ PARCBuffer *object2 = parcBuffer_WrapCString("2");
+ PARCBuffer *object3 = parcBuffer_WrapCString("3");
+
+ PARCSortedList *deque = parcSortedList_Create();
+ parcSortedList_Add(deque, object1);
+ parcSortedList_Add(deque, object2);
+ parcSortedList_Add(deque, object3);
+
+ PARCBuffer *peek = parcSortedList_RemoveLast(deque);
+ assertTrue(parcBuffer_Equals(object3, peek),
+ "Objects out of order.");
+
+ parcBuffer_Release(&peek);
+
+ parcBuffer_Release(&object1);
+ parcBuffer_Release(&object2);
+ parcBuffer_Release(&object3);
+ parcSortedList_Release(&deque);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSortedList_RemoveLast_SingleElement)
+{
+ PARCBuffer *object1 = parcBuffer_WrapCString("1");
+
+ PARCSortedList *deque = parcSortedList_Create();
+ parcSortedList_Add(deque, object1);
+
+ PARCBuffer *peek = parcSortedList_RemoveLast(deque);
+ assertTrue(parcBuffer_Equals(object1, peek),
+ "Objects out of order.");
+
+ parcBuffer_Release(&object1);
+ parcSortedList_Release(&deque);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_SortedList);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Stack.c b/libparc/parc/algol/test/test_parc_Stack.c
new file mode 100755
index 00000000..3ca27682
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Stack.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.
+ */
+
+/**
+ * @header <#Headline Name#>
+ * @abstract <#Abstract#>
+ * @discussion
+ * <#Discussion#>
+ *
+ */
+#include "../parc_Stack.c"
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Deque.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(test_parc_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(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_parc_Stack)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_Stack)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcStack_IsEmpty_PARCDeque);
+ LONGBOW_RUN_TEST_CASE(Global, parcStack_IsEmpty_PARCArrayList);
+}
+
+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, parcStack_IsEmpty_PARCDeque)
+{
+ PARCStackInterface dequeAsStack = {
+ .parcStack_Release = (void (*)(void **))parcDeque_Release,
+ .parcStack_IsEmpty = (bool (*)(const void *))parcDeque_IsEmpty,
+ .parcStack_Peek = (void *(*)(const void *))parcDeque_PeekLast,
+ .parcStack_Pop = (void *(*)(void *))parcDeque_RemoveLast,
+ .parcStack_Push = (void *(*)(void *, void *))parcDeque_Append,
+ .parcStack_Search = NULL
+ };
+
+ PARCStack *stack = parcStack(parcDeque_Create(), &dequeAsStack);
+
+ bool actual = parcStack_IsEmpty(stack);
+ parcStack_Release(&stack);
+ assertTrue(actual, "Expected the stack to be empty.");
+}
+
+LONGBOW_TEST_CASE(Global, parcStack_IsEmpty_PARCArrayList)
+{
+ PARCStackInterface arrayListAsStack = {
+ .parcStack_Release = (void (*)(void **))parcArrayList_Destroy,
+ .parcStack_IsEmpty = (bool (*)(const void *))parcArrayList_IsEmpty,
+ .parcStack_Peek = (void *(*)(const void *))parcArrayList_Peek,
+ .parcStack_Pop = (void *(*)(void *))parcArrayList_Pop,
+ .parcStack_Push = (void *(*)(void *, void *))parcArrayList_Add,
+ .parcStack_Search = NULL
+ };
+
+ PARCStack *stack = parcStack(parcArrayList_Create(NULL), &arrayListAsStack);
+
+ bool actual = parcStack_IsEmpty(stack);
+ parcStack_Release(&stack);
+ assertTrue(actual, "Expected the stack to be empty.");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_Stack);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_StdlibMemory.c b/libparc/parc/algol/test/test_parc_StdlibMemory.c
new file mode 100644
index 00000000..7cf49991
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_StdlibMemory.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 "../parc_StdlibMemory.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+
+LONGBOW_TEST_RUNNER(test_parc_StdlibMemory)
+{
+ // 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(Threads);
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_parc_StdlibMemory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_StdlibMemory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_Allocate);
+ LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_MemAlign_BadAlignment);
+ LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_MemAlign_BadSize);
+ LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_AllocateAndClear);
+ LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_AllocateAndClear_BadSize);
+ LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_Reallocate);
+ LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_Reallocate_NULL);
+ LONGBOW_RUN_TEST_CASE(Global, parcStdlibMemory_StringDuplicate);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaks allocations.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcStdlibMemory_Allocate)
+{
+ size_t size = 100;
+
+ void *result = parcStdlibMemory_Allocate(size);
+
+ assertNotNull(result, "parcStdlibMemory_Allocate failed: NULL result.");
+ assertTrue(parcStdlibMemory_Outstanding() == 1,
+ "Expected 1 outstanding allocation, actual %d", parcStdlibMemory_Outstanding());
+ parcStdlibMemory_Deallocate(&result);
+}
+
+LONGBOW_TEST_CASE(Global, parcStdlibMemory_MemAlign_BadAlignment)
+{
+ void *result;
+ size_t alignment = 3;
+ size_t size = 1200;
+
+ int failure = parcStdlibMemory_MemAlign(&result, alignment, size);
+ assertTrue(failure == EINVAL,
+ "parcStdlibMemory_Allocate failed to report bad aligment specification");
+ assertTrue(parcStdlibMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocations, actual %d", parcStdlibMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcStdlibMemory_MemAlign_BadSize)
+{
+ void *result;
+ size_t alignment = sizeof(void *);
+ size_t size = 0;
+
+ int failure = parcStdlibMemory_MemAlign(&result, alignment, size);
+ assertTrue(failure == EINVAL,
+ "parcStdlibMemory_Allocate failed to report bad aligment specification");
+ assertTrue(parcStdlibMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocation, actual %d", parcStdlibMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcStdlibMemory_AllocateAndClear)
+{
+ size_t size = 1200;
+
+ void *result = parcStdlibMemory_AllocateAndClear(size);
+ assertNotNull(result, "parcStdlibMemory_Allocate failed: NULL result.");
+
+ for (size_t i = 0; i < size; i++) {
+ assertTrue(((char *) result)[i] == 0,
+ "parcStdlibMemory_AllocateAndClear failed to zero memory at index %zd", i);
+ }
+ assertTrue(parcStdlibMemory_Outstanding() == 1,
+ "Expected 1 outstanding allocation, actual %d", parcStdlibMemory_Outstanding());
+ parcStdlibMemory_Deallocate(&result);
+ assertTrue(parcStdlibMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocation, actual %d", parcStdlibMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcStdlibMemory_AllocateAndClear_BadSize)
+{
+ void *result;
+ size_t alignment = sizeof(void *);
+ size_t size = 0;
+
+ int failure = parcStdlibMemory_MemAlign(&result, alignment, size);
+ assertTrue(failure == EINVAL,
+ "parcStdlibMemory_Allocate failed to report bad aligment specification");
+ assertTrue(parcStdlibMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocations, actual %d", parcStdlibMemory_Outstanding());
+}
+
+static void
+_test_SetMemory(unsigned char *memory, size_t size)
+{
+ for (size_t i = 0; i < size; i++) {
+ memory[i] = i;
+ }
+}
+
+static void
+_test_CheckMemory(unsigned char *memory, size_t size)
+{
+ for (size_t i = 0; i < size; i++) {
+ assertTrue(memory[i] == (i % 256), "memory failed to check at index %zd", i);
+ }
+}
+
+
+LONGBOW_TEST_CASE(Global, parcStdlibMemory_Reallocate)
+{
+ size_t size = 1200;
+
+ void *result = parcStdlibMemory_AllocateAndClear(size);
+ assertNotNull(result,
+ "parcStdlibMemory_Allocate failed: NULL result.");
+
+ _test_SetMemory(result, size);
+ _test_CheckMemory(result, size);
+
+ result = parcStdlibMemory_Reallocate(result, size * 2);
+
+ _test_CheckMemory(result, size);
+
+ assertTrue(parcStdlibMemory_Outstanding() == 1,
+ "Expected 1 outstanding allocation, actual %d", parcStdlibMemory_Outstanding());
+ parcStdlibMemory_Deallocate(&result);
+ assertTrue(parcStdlibMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocations, actual %d", parcStdlibMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcStdlibMemory_Reallocate_NULL)
+{
+ void *result = NULL;
+ size_t size = 1200;
+
+ result = parcStdlibMemory_Reallocate(result, size * 2);
+ _test_SetMemory(result, size * 2);
+ _test_CheckMemory(result, size * 2);
+
+ assertTrue(parcStdlibMemory_Outstanding() == 1,
+ "Expected 1 outstanding allocation, actual %d", parcStdlibMemory_Outstanding());
+ parcStdlibMemory_Deallocate(&result);
+ assertTrue(parcStdlibMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocations, actual %d", parcStdlibMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, parcStdlibMemory_StringDuplicate)
+{
+ char *expected = "Hello World";
+ char *actual = parcStdlibMemory_StringDuplicate(expected, strlen(expected));
+
+ assertTrue(expected != actual,
+ "Expected a distinct pointer unequal to the original string");
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected strings to be equal. '%s' vs '%s'", expected, actual);
+
+ assertTrue(parcStdlibMemory_Outstanding() == 1,
+ "Expected 1 outstanding allocation, actual %d", parcStdlibMemory_Outstanding());
+ parcStdlibMemory_Deallocate((void **) &actual);
+ assertTrue(parcStdlibMemory_Outstanding() == 0,
+ "Expected 0 outstanding allocations, actual %d", parcStdlibMemory_Outstanding());
+}
+
+LONGBOW_TEST_FIXTURE(Threads)
+{
+ LONGBOW_RUN_TEST_CASE(Threads, Threads1000);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Threads)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Threads)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+void *
+allocator(void *unused)
+{
+ for (int i = 0; i < 1000; i++) {
+ void *memory = parcStdlibMemory_Allocate(10);
+ parcStdlibMemory_Deallocate(&memory);
+ }
+ return 0;
+}
+
+LONGBOW_TEST_CASE(Threads, Threads1000)
+{
+#define NTHREADS 1000
+ pthread_t thread[NTHREADS];
+
+ for (int i = 0; i < NTHREADS; i++) {
+ pthread_create(&thread[i], NULL, allocator, NULL);
+ }
+ for (int i = 0; i < NTHREADS; i++) {
+ pthread_join(thread[0], NULL);
+ }
+}
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcStdlibMemory_AllocateDeallocate_Forward);
+ LONGBOW_RUN_TEST_CASE(Performance, parcStdlibMemory_AllocateDeallocate_Reverse);
+ LONGBOW_RUN_TEST_CASE(Performance, parcStdlibMemory_MemAlignDeallocate_Forward);
+ LONGBOW_RUN_TEST_CASE(Performance, parcStdlibMemory_MemAlignDeallocate_Reverse);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+#define ELEMENT_COUNT 1000000
+#define ELEMENT_SIZE 151
+void *memory[ELEMENT_COUNT];
+
+LONGBOW_TEST_CASE(Performance, parcStdlibMemory_AllocateDeallocate_Forward)
+{
+ for (int i = 0; i < ELEMENT_COUNT; i++) {
+ memory[i] = parcStdlibMemory_Allocate(ELEMENT_SIZE);
+ }
+ for (int i = 0; i < ELEMENT_COUNT; i++) {
+ parcStdlibMemory_Deallocate(&memory[i]);
+ }
+}
+
+LONGBOW_TEST_CASE(Performance, parcStdlibMemory_AllocateDeallocate_Reverse)
+{
+ for (int i = 0; i < ELEMENT_COUNT; i++) {
+ memory[i] = parcStdlibMemory_Allocate(ELEMENT_SIZE);
+ }
+
+ int i = ELEMENT_COUNT;
+ do {
+ i--;
+ parcStdlibMemory_Deallocate(&memory[i]);
+ } while (i > 0);
+}
+
+LONGBOW_TEST_CASE(Performance, parcStdlibMemory_MemAlignDeallocate_Forward)
+{
+ for (int i = 0; i < ELEMENT_COUNT; i++) {
+ parcStdlibMemory_MemAlign(&memory[i], sizeof(void *), ELEMENT_SIZE);
+ }
+ for (int i = 0; i < ELEMENT_COUNT; i++) {
+ parcStdlibMemory_Deallocate(&memory[i]);
+ }
+}
+
+LONGBOW_TEST_CASE(Performance, parcStdlibMemory_MemAlignDeallocate_Reverse)
+{
+ for (int i = 0; i < ELEMENT_COUNT; i++) {
+ parcStdlibMemory_MemAlign(&memory[i], sizeof(void *), ELEMENT_SIZE);
+ }
+
+ int i = ELEMENT_COUNT;
+ do {
+ i--;
+ parcStdlibMemory_Deallocate(&memory[i]);
+ } while (i > 0);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_StdlibMemory);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_String.c b/libparc/parc/algol/test/test_parc_String.c
new file mode 100644
index 00000000..84d3d3da
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_String.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 "../parc_String.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(parc_String)
+{
+ // 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(parc_String)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_String)
+{
+ 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)
+{
+ PARCString *instance = parcString_Create("Hello World");
+ assertNotNull(instance, "Expected non-null result from parcString_Create();");
+ parcObjectTesting_AssertAcquireReleaseImpl(instance);
+
+ parcString_Release(&instance);
+ assertNull(instance, "Expected null result from parcString_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcString_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcString_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcString_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcString_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcString_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcString_IsValid);
+ LONGBOW_RUN_TEST_CASE(Global, parcString_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Global, parcString_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, parcString_Compare)
+{
+ PARCString *string = parcString_Create("Hello1");
+ PARCString *equivalent[2] = {
+ parcString_Create("Hello1"),
+ NULL
+ };
+ PARCString *greater[2] = {
+ parcString_Create("Hello2"),
+ NULL
+ };
+ PARCString *lesser[2] = {
+ parcString_Create("Hello0"),
+ NULL
+ };
+
+ parcObjectTesting_AssertCompareTo(parcString_Compare, string, equivalent, lesser, greater);
+ parcString_Release(&string);
+ parcString_Release(&equivalent[0]);
+ parcString_Release(&greater[0]);
+ parcString_Release(&lesser[0]);
+}
+
+LONGBOW_TEST_CASE(Global, parcString_Copy)
+{
+ PARCString *instance = parcString_Create("Hello World");
+ PARCString *copy = parcString_Copy(instance);
+ assertTrue(parcString_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcString_Release(&instance);
+ parcString_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, parcString_Display)
+{
+ PARCString *instance = parcString_Create("Hello World");
+ parcString_Display(instance, 0);
+ parcString_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcString_Equals)
+{
+ PARCString *x = parcString_Create("Hello World");
+ PARCString *y = parcString_Create("Hello World");
+ PARCString *z = parcString_Create("Hello World");
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcString_Release(&x);
+ parcString_Release(&y);
+ parcString_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Global, parcString_HashCode)
+{
+ PARCString *x = parcString_Create("Hello World");
+ PARCString *y = parcString_Create("Hello World");
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcString_Release(&x);
+ parcString_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Global, parcString_IsValid)
+{
+ PARCString *instance = parcString_Create("Hello World");
+ assertTrue(parcString_IsValid(instance), "Expected parcString_Create to result in a valid instance.");
+
+ parcString_Release(&instance);
+ assertFalse(parcString_IsValid(instance), "Expected parcString_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcString_ToJSON)
+{
+ PARCString *instance = parcString_Create("Hello World");
+
+ PARCJSON *json = parcString_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcString_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcString_ToString)
+{
+ PARCString *instance = parcString_Create("Hello World");
+
+ char *string = parcString_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcString_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcString_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_String);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libparc/parc/algol/test/test_parc_Time.c b/libparc/parc/algol/test/test_parc_Time.c
new file mode 100644
index 00000000..2befdde1
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Time.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 <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_Memory.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Time.c"
+
+LONGBOW_TEST_RUNNER(test_parc_Time)
+{
+ // 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_parc_Time)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_Time)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcTime_TimevalAsString);
+ LONGBOW_RUN_TEST_CASE(Global, parcTime_TimevalAsISO8601);
+ LONGBOW_RUN_TEST_CASE(Global, parcTime_TimevalAsRFC3339);
+ LONGBOW_RUN_TEST_CASE(Global, parcTime_RFC3339_Now);
+ LONGBOW_RUN_TEST_CASE(Global, parcTime_NowTimeval);
+ LONGBOW_RUN_TEST_CASE(Global, parcTime_NowMicroseconds);
+}
+
+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, parcTime_TimevalAsString)
+{
+ struct timeval timeval;
+ timeval.tv_sec = 0;
+ timeval.tv_usec = 1000;
+
+ char *expected = "0.001000";
+ char *actual = parcTime_TimevalAsString(timeval);
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcTime_TimevalAsISO8601)
+{
+ struct timeval timeval;
+ timeval.tv_sec = 0;
+ timeval.tv_usec = 1000;
+
+ char *expected = "1970-01-01 00:00:00.001000Z";
+
+ char actual[64];
+ parcTime_TimevalAsISO8601(&timeval, actual);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcTime_TimevalAsRFC3339)
+{
+ struct timeval timeval;
+ timeval.tv_sec = 0;
+ timeval.tv_usec = 1000;
+
+ char *expected = "1970-01-01T00:00:00.001000Z";
+
+ char actual[64];
+ parcTime_TimevalAsRFC3339(&timeval, actual);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcTime_RFC3339_Now)
+{
+ struct timeval timeval;
+ gettimeofday(&timeval, NULL);
+
+ char actual[64];
+ parcTime_TimevalAsRFC3339(&timeval, actual);
+ printf("%s\n", actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcTime_NowTimeval)
+{
+ struct timeval result = parcTime_NowTimeval();
+ assertTrue(result.tv_sec != 0, "Expected NOW to not be zero.");
+}
+
+LONGBOW_TEST_CASE(Global, parcTime_NowMicroseconds)
+{
+ uint64_t result = parcTime_NowMicroseconds();
+ assertTrue(result != 0, "Expected NOW to not be zero.");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_Time);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_TreeMap.c b/libparc/parc/algol/test/test_parc_TreeMap.c
new file mode 100755
index 00000000..9355380b
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_TreeMap.c
@@ -0,0 +1,1565 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <time.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include "../parc_TreeMap.c"
+
+
+typedef struct {
+ int value;
+} _Int;
+
+static _Int *
+_int_Copy(const _Int *source);
+
+static bool
+_int_Equals(const _Int *a, const _Int *b)
+{
+ return a->value == b->value;
+}
+
+static int
+_int_Compare(const _Int *a, const _Int *b)
+{
+ int result = 0;
+ if (a->value > b->value) {
+ result = 1;
+ } else if (a->value < b->value) {
+ result = -1;
+ }
+
+ return result;
+}
+
+parcObject_ExtendPARCObject(_Int, NULL, _int_Copy, NULL, _int_Equals, _int_Compare, NULL, NULL);
+
+static
+parcObject_ImplementRelease(_int, _Int);
+
+static _Int *
+_int_Create(const int value)
+{
+ _Int *newObj = parcObject_CreateInstance(_Int);
+ assertNotNull(newObj, "parcMemory_Allocate(%zu) returned NULL", sizeof(int));
+ newObj->value = value;
+ return newObj;
+}
+
+static _Int *
+_int_Copy(const _Int *source)
+{
+ return _int_Create(source->value);
+}
+
+static _Int *
+_int_Set(_Int *obj, const int value)
+{
+ obj->value = value;
+ return obj;
+}
+static PARCBuffer*
+strBuf(char *key)
+{
+ return parcBuffer_WrapCString(key);
+}
+
+
+LONGBOW_TEST_RUNNER(PARC_TreeMap)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(Stress);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(PARC_TreeMap)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ int seed = (int) time(NULL);
+ srandom(seed);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(PARC_TreeMap)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Create);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_Ordered);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Put_Release);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Put_Ordered);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Put_OutOfOrder);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Put_Overwrite);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_ReleaseTillEmpty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Size_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Size);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Size_Overwrite);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_EmptyTree);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_NonExistent);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_Biggest);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Get_Smallest);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_FirstKey);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_FirstEntry);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_LastKey);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_LastEntry);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_FirstKey_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_LastKey_Empty);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_LowerEntry);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_LowerKey);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_HigherEntry);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_HigherKey);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_NonExistent);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_NonExistent);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_WithSuccessorNonRoot);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_LeftChildRightChild);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Keys);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Values);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Equals_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Equals_DifferentLength);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Equals_Not_Values);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Equals_Not_Keys);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Copy_Direct);
+
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Iterator);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_ValueIterator);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_KeyIterator);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_Using_Iterator);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeMap_Remove_Element_Using_Iterator);
+}
+
+#define N_TEST_ELEMENTS 42
+
+typedef struct {
+ PARCTreeMap *testMap1;
+ PARCTreeMap *testMap2;
+ _Int *k[N_TEST_ELEMENTS];
+ _Int *v[N_TEST_ELEMENTS];
+} TestData;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ data->testMap1 = parcTreeMap_Create();
+ data->testMap2 = parcTreeMap_CreateCustom((PARCTreeMap_CustomCompare *) _int_Compare);
+
+ for (int i = 0; i < N_TEST_ELEMENTS; ++i) {
+ data->k[i] = _int_Create(i);
+ data->v[i] = _int_Create(i + 1000);
+ }
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcTreeMap_Release(&data->testMap1);
+ parcTreeMap_Release(&data->testMap2);
+
+ for (int i = 0; i < N_TEST_ELEMENTS; ++i) {
+ _int_Release(&(data->k[i]));
+ _int_Release(&(data->v[i]));
+ }
+
+ 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;
+}
+
+static
+int
+recursiveCheckBlackDepth(const PARCTreeMap *tree, const _RBNode *node)
+{
+ assertNotNull(tree, "Null tree?\n");
+ assertNotNull(node, "Null node?\n");
+ if (node == tree->nil) {
+ return 0;
+ }
+ int right_depth = recursiveCheckBlackDepth(tree, node->rightChild);
+ int left_depth = recursiveCheckBlackDepth(tree, node->leftChild);
+ assertTrue(right_depth == left_depth, "Wrong depth!!\n");
+ if (_rbNodeColor(node) == BLACK) {
+ return right_depth + 1;
+ }
+ return right_depth;
+}
+
+static
+void
+rbCheckTree(const PARCTreeMap *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ _rbNodeAssertTreeInvariants(tree);
+ if (tree->size > 0) {
+ recursiveCheckBlackDepth(tree, tree->root);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_Ordered)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+
+ for (int i = 0; i < 16; i++) {
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ for (int i = 0; i < 14; i++) {
+ //rbPrintTreeString(tree1);
+ PARCObject *value = parcTreeMap_Remove(tree1, data->k[i]);
+ assertNotNull(value, "Data is null!");
+ assertTrue(_int_Equals(value, data->v[i]), "Expect the ordered value.");
+ parcObject_Release(&value);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Create)
+{
+ PARCTreeMap *map = parcTreeMap_Create();
+ parcTreeMap_Release(&map);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Acquire)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *map = parcTreeMap_Acquire(data->testMap1);
+ parcTreeMap_Release(&map);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Put_Release)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree = data->testMap1;
+
+ PARCBuffer *value1 = strBuf("value 1");
+ PARCBuffer *key1 = strBuf("1");
+ PARCBuffer *value2 = strBuf("value 2");
+ PARCBuffer *key2 = strBuf("2");
+ PARCBuffer *value3 = strBuf("value 3");
+ PARCBuffer *key3 = strBuf("3");
+
+ parcTreeMap_Put(tree, key1, value1);
+ parcTreeMap_Put(tree, key2, value2);
+ parcTreeMap_Put(tree, key3, value3);
+
+ parcBuffer_Release(&key1);
+ parcBuffer_Release(&value1);
+ parcBuffer_Release(&key2);
+ parcBuffer_Release(&value2);
+ parcBuffer_Release(&key3);
+ parcBuffer_Release(&value3);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Put_Overwrite)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree = data->testMap1;
+
+ parcTreeMap_Put(tree, data->k[1], data->v[1]);
+ parcTreeMap_Put(tree, data->k[2], data->v[2]);
+ parcTreeMap_Put(tree, data->k[3], data->v[3]);
+ parcTreeMap_Put(tree, data->k[3], data->v[4]);
+ parcTreeMap_Put(tree, data->k[3], data->v[5]);
+
+ assertTrue(3 == parcTreeMap_Size(tree), "Wrong size of tree should stay at 3");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Put_Ordered)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree = data->testMap1;
+
+ parcTreeMap_Put(tree, data->k[1], data->v[1]);
+ parcTreeMap_Put(tree, data->k[2], data->v[2]);
+ parcTreeMap_Put(tree, data->k[3], data->v[3]);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Put_OutOfOrder)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+
+ parcTreeMap_Put(tree1, data->k[4], data->v[4]);
+ parcTreeMap_Put(tree1, data->k[2], data->v[2]);
+ parcTreeMap_Put(tree1, data->k[3], data->v[3]);
+ parcTreeMap_Put(tree1, data->k[1], data->v[1]);
+
+ PARCTreeMap *tree2 = data->testMap2;
+ parcTreeMap_Put(tree2, data->k[1], data->v[1]);
+ parcTreeMap_Put(tree2, data->k[3], data->v[3]);
+ parcTreeMap_Put(tree2, data->k[2], data->v[2]);
+ parcTreeMap_Put(tree2, data->k[4], data->v[4]);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Expect trees to be Equal");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Size_Empty)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree = data->testMap1;
+
+ assertTrue(0 == parcTreeMap_Size(tree), "Wrong size of tree - empty, start");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Size)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree = data->testMap1;
+
+ parcTreeMap_Put(tree, data->k[4], data->v[4]);
+ parcTreeMap_Put(tree, data->k[2], data->v[2]);
+ parcTreeMap_Put(tree, data->k[3], data->v[3]);
+
+ assertTrue(3 == parcTreeMap_Size(tree), "Wrong size of tree after add 3");
+
+ parcTreeMap_Put(tree, data->k[1], data->v[1]);
+
+ assertTrue(4 == parcTreeMap_Size(tree), "Wrong size of tree after add 1 more");
+
+ parcTreeMap_RemoveAndRelease(tree, data->k[2]);
+
+ size_t size = parcTreeMap_Size(tree);
+
+ assertTrue(3 == size, "Wrong size of tree after 1 delete (%zu instead of 3)", size);
+
+ parcTreeMap_Put(tree, data->k[7], data->v[7]);
+
+ assertTrue(4 == parcTreeMap_Size(tree), "Wrong size of tree after add 1 more");
+
+ parcTreeMap_RemoveAndRelease(tree, data->k[3]);
+ assertTrue(3 == parcTreeMap_Size(tree), "Wrong size of tree after del 1 more - 3");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_ReleaseTillEmpty)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ // This order of puts are removes exercises code paths
+ // in TreeMap not exercised in any other place.
+ int idx1a[7] = { 4, 2, 3, 1, 5, 7, 6 };
+ int idx1b[7] = { 3, 1, 4, 2, 6, 5, 7 };
+ int idx2a[7] = { 4, 6, 5, 7, 3, 1, 2 };
+ int idx2b[7] = { 5, 7, 4, 6, 2, 3, 1 };
+
+ for (int i = 0; i < 7; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[idx1a[i]], data->v[idx1a[i]]);
+ parcTreeMap_Put(tree2, data->k[idx2a[i]], data->v[idx2a[i]]);
+ }
+
+ for (int i = 0; i < 7; ++i) {
+ parcTreeMap_RemoveAndRelease(tree1, data->k[idx1b[i]]);
+ parcTreeMap_RemoveAndRelease(tree2, data->k[idx2b[i]]);
+ }
+
+ size_t size;
+ size = parcTreeMap_Size(tree1);
+
+ assertTrue(0 == size, "Wrong size of tree - empty (got %zu)", size);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Size_Overwrite)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree = data->testMap1;
+
+ parcTreeMap_Put(tree, data->k[4], data->v[4]);
+ parcTreeMap_Put(tree, data->k[2], data->v[2]);
+ parcTreeMap_Put(tree, data->k[3], data->v[3]);
+
+ // Size is 3 here, we'll insert the same number now..
+
+ parcTreeMap_Put(tree, data->k[3], data->v[23]);
+
+ assertTrue(3 == parcTreeMap_Size(tree), "Wrong size of tree after overwrite");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_EmptyTree)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree = data->testMap1;
+
+ PARCObject *value = parcTreeMap_Get(tree, data->k[1]);
+
+ assertTrue(NULL == value, "Object did not exist, must return NULL");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_NonExistent)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCObject *value = parcTreeMap_Get(tree, data->k[23]);
+
+ assertTrue(NULL == value, "Object did not exist, must return NULL");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_First)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 1; i < 4; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCObject *value = parcTreeMap_Get(tree, data->k[1]);
+
+ assertTrue(_int_Equals(data->v[1], value), "Wrong value, got %ld", (long) value);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCObject *value = parcTreeMap_Get(tree, data->k[4]);
+
+ assertTrue(_int_Equals(data->v[4], value), "Wrong value, got %ld", (long) value);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_Last)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCObject *value = parcTreeMap_Get(tree, data->k[9]);
+
+ assertTrue(_int_Equals(data->v[9], value), "Wrong value, got %ld", (long) value);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_Smallest)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+
+ PARCObject *value = parcTreeMap_Get(tree, data->k[1]);
+
+ assertTrue(_int_Equals(data->v[1], value), "Wrong value, got %ld", (long) value);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Get_Biggest)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCObject *value = parcTreeMap_Get(tree, data->k[39]);
+
+ assertTrue(_int_Equals(data->v[39], value), "Wrong value, got %ld", (long) value);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_FirstEntry)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCKeyValue *entry = parcTreeMap_GetFirstEntry(tree);
+
+ assertTrue(_int_Equals(data->k[1], parcKeyValue_GetKey(entry)),
+ "Wrong value, got %ld", (long) parcKeyValue_GetKey(entry));
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_FirstKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCObject *key = parcTreeMap_GetFirstKey(tree);
+
+ assertTrue(_int_Equals(data->k[1], key), "Wrong value, got %ld", (long) key);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_FirstKey_Empty)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ PARCObject *key = parcTreeMap_GetFirstKey(tree);
+
+ assertNull(key, "Should get NULL on empty tree");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_LastKey_Empty)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ PARCObject *key = parcTreeMap_GetLastKey(tree);
+
+ assertNull(key, "Should get NULL on empty tree");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_LastEntry)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCKeyValue *entry = parcTreeMap_GetLastEntry(tree);
+
+ assertTrue(_int_Equals(data->k[39], parcKeyValue_GetKey(entry)),
+ "Wrong value, got %ld", (long) parcKeyValue_GetKey(entry));
+}
+
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_LastKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree = data->testMap1;
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree, data->k[i], data->v[i]);
+ }
+
+ PARCObject *key = parcTreeMap_GetLastKey(tree);
+
+ assertTrue(_int_Equals(data->k[39], key), "Wrong value, got %ld", (long) key);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_First)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_Put(tree1, data->k[1], data->v[1]);
+
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ PARCObject *value = parcTreeMap_Remove(tree1, data->k[1]);
+ parcObject_Release(&value);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 31; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_Put(tree1, data->k[30], data->v[30]);
+
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ PARCObject *value = parcTreeMap_Remove(tree1, data->k[30]);
+ parcObject_Release(&value);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_Last)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_Put(tree1, data->k[41], data->v[41]);
+
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ PARCObject *value = parcTreeMap_Remove(tree1, data->k[41]);
+ assertNotNull(value, "Expected to find some object.");
+ assertTrue(_int_Equals(data->v[41], value), "Expected value 41 in return");
+ parcObject_Release(&value);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees don't match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_First)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_Put(tree1, data->k[1], data->v[1]);
+
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_RemoveAndRelease(tree1, data->k[1]);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 31; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_Put(tree1, data->k[30], data->v[30]);
+
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_RemoveAndRelease(tree1, data->k[30]);
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+
+ for (int i = 20; i < 30; i++) {
+ parcTreeMap_RemoveAndRelease(tree1, data->k[i]);
+ parcTreeMap_RemoveAndRelease(tree2, data->k[49 - i]);
+ }
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+
+ for (int i = 2; i < 10; i++) {
+ parcTreeMap_RemoveAndRelease(tree1, data->k[i]);
+ parcTreeMap_RemoveAndRelease(tree2, data->k[11 - i]);
+ }
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+
+ for (int i = 31; i < 40; i++) {
+ parcTreeMap_RemoveAndRelease(tree1, data->k[i]);
+ parcTreeMap_RemoveAndRelease(tree2, data->k[70 - i]);
+ }
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_NonExistent)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ PARCObject *element = parcTreeMap_Remove(tree1, data->k[0]);
+
+ assertNull(element, "Return value must be NULL on non existing element");
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_NonExistent)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_RemoveAndRelease(tree1, data->k[0]);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_WithSuccessorNonRoot)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+ int idx2[13] = { 8, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]);
+ }
+
+ for (int i = 0; i < 13; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree2, data->k[idx2[i]], data->v[idx2[i]]);
+ }
+
+ _Int *key = _int_Create(4);
+ parcTreeMap_RemoveAndRelease(tree1, key);
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 12));
+ _int_Release(&key);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_LeftChildRightChild)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]);
+ parcTreeMap_Put(tree2, data->k[idx1[i]], data->v[idx1[i]]);
+ }
+
+ _Int *key = _int_Create(0);
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 13));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 7));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 14));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 6));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 15));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 12));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 11));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 10));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 9));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 8));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 5));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 4));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 3));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 2));
+ parcTreeMap_RemoveAndRelease(tree1, _int_Set(key, 1));
+
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 1));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 2));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 3));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 4));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 5));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 6));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 7));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 8));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 9));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 10));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 11));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 12));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 13));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 14));
+ parcTreeMap_RemoveAndRelease(tree2, _int_Set(key, 15));
+ _int_Release(&key);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_RemoveAndRelease_Last)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ parcTreeMap_Put(tree1, data->k[41], data->v[41]);
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_RemoveAndRelease(tree1, data->k[41]);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Trees dont match after remove");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_LowerEntry)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ // Empty Tree
+ PARCKeyValue *kv = parcTreeMap_GetLowerEntry(tree1, data->k[23]);
+ assertNull(kv, "Expected a NULL return for LowerEntry() on empty tree");
+
+ // Fill Tree
+ int max = N_TEST_ELEMENTS - 1;
+ for (int i = 21; i <= max; ++i) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+ for (int i = 1; i < 21; ++i) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ // Using lowest key in tree
+ kv = parcTreeMap_GetLowerEntry(tree1, data->k[1]);
+ assertNull(kv, "Expected a NULL return for no lower entry");
+
+ // On all entries except the lowest tree
+ for (int i = max; i > 1; --i) {
+ kv = parcTreeMap_GetLowerEntry(tree1, data->k[i]);
+ assertNotNull(kv, "Expected a lower entry to exist");
+ _Int *key = (_Int *) parcKeyValue_GetKey(kv);
+ assertTrue(_int_Equals(key, data->k[i - 1]),
+ "Expected entry with key %d, got %d",
+ data->k[i - 1]->value, key->value);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_LowerKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ // Empty Tree
+ _Int *key = (_Int *) parcTreeMap_GetLowerKey(tree1, data->k[23]);
+ assertNull(key, "Expected a NULL return for LowerEntry() on empty tree");
+
+ int max = N_TEST_ELEMENTS - 1;
+ for (int i = 21; i <= max; ++i) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+ for (int i = 1; i < 21; ++i) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ // Using lowest key in tree
+ key = (_Int *) parcTreeMap_GetLowerKey(tree1, data->k[1]);
+ assertNull(key, "Expected a NULL return for no lower entry");
+
+ // On all entries except the lowest tree
+ for (int i = max; i > 1; --i) {
+ key = parcTreeMap_GetLowerKey(tree1, data->k[i]);
+ assertNotNull(key, "Expected a lower entry to exist");
+ assertTrue(_int_Equals(key, data->k[i - 1]),
+ "Expected entry with key %d, got %d",
+ data->k[i - 1]->value, key->value);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_HigherEntry)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ // Empty Tree
+ PARCKeyValue *kv = parcTreeMap_GetHigherEntry(tree1, data->k[23]);
+ assertNull(kv, "Expected a NULL return for HigherEntry() on empty tree");
+
+ int max = N_TEST_ELEMENTS - 2;
+ for (int i = 21; i <= max; ++i) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+ for (int i = 1; i < 21; ++i) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ // Using highest key in tree
+ kv = parcTreeMap_GetHigherEntry(tree1, data->k[max]);
+ assertNull(kv, "Expected a NULL return for no higher entry");
+
+ // On all entries except the lowest tree
+ for (int i = 1; i < max; ++i) {
+ kv = parcTreeMap_GetHigherEntry(tree1, data->k[i]);
+ assertNotNull(kv, "Expected a higher entry to exist");
+ _Int *key = (_Int *) parcKeyValue_GetKey(kv);
+ assertTrue(_int_Equals(key, data->k[i + 1]),
+ "Expected entry with key %d, got %d",
+ data->k[i + 1]->value, key->value);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_HigherKey)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ // Empty Tree
+ _Int *key = (_Int *) parcTreeMap_GetHigherKey(tree1, data->k[23]);
+ assertNull(key, "Expected a NULL return for LowerEntry() on empty tree");
+
+ int max = N_TEST_ELEMENTS - 2;
+ for (int i = 21; i <= max; ++i) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+ for (int i = 1; i < 21; ++i) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ key = (_Int *) parcTreeMap_GetHigherEntry(tree1, data->k[max]);
+ assertNull(key, "Expected a NULL return for no higher entry");
+
+ for (int i = 1; i < max; ++i) {
+ key = (_Int *) parcTreeMap_GetHigherKey(tree1, data->k[i]);
+ assertNotNull(key, "Expected a higher entry to exist");
+ assertTrue(_int_Equals(key, data->k[i + 1]),
+ "Expected entry with key %d, got %d",
+ data->k[i + 1]->value, key->value);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Keys)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+
+ PARCList *list = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList);
+
+ // Insert in tree out of order
+ for (int i = 10; i < 20; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+ for (int i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ // Insert in list in order
+ for (int i = 1; i < 20; i++) {
+ // Add some elements to the tree
+ parcList_Add(list, data->k[i]);
+ }
+
+ PARCList *keys = parcTreeMap_AcquireKeys(tree1);
+
+ assertTrue(parcList_Equals(list, keys), "Key list doesnt' match");
+
+ parcList_Release(&keys);
+ parcList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Values)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+
+ PARCList *list = parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList);
+
+ // Insert in tree out of order
+ for (int i = 10; i < 20; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+ for (int i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ // Insert in list in order
+ for (int i = 1; i < 20; i++) {
+ // Add some elements to the tree
+ parcList_Add(list, data->v[i]);
+ }
+
+ PARCList *values = parcTreeMap_AcquireValues(tree1);
+
+ assertTrue(parcList_Equals(list, values), "Key list doesnt' match");
+
+ parcList_Release(&values);
+ parcList_Release(&list);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Equals_Empty)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Empty lists are not equal");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Equals_DifferentLength)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+
+ for (int i = 1; i < 20; i++) {
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[i]);
+ }
+
+ parcTreeMap_Put(tree2, data->k[41], data->v[41]);
+
+ assertFalse(parcTreeMap_Equals(tree1, tree2), "Lists are equal");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Equals_Not_Values)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 1; i < 20; i++) {
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i], data->v[20 - i]);
+ }
+
+ assertFalse(parcTreeMap_Equals(tree1, tree2), "Lists are equal");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Equals_Not_Keys)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 1; i < 20; i++) {
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[i + 1], data->v[i]);
+ }
+ assertTrue(parcTreeMap_Size(tree1) == parcTreeMap_Size(tree2), "Expect trees to have the same size.");
+
+ assertFalse(parcTreeMap_Equals(tree1, tree2), "Lists should not be equal");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Equals)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap2;
+
+ for (int i = 1; i < 40; i++) {
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ parcTreeMap_Put(tree2, data->k[40 - i], data->v[40 - i]);
+ }
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Lists are not equal");
+}
+
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Copy)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *treeCopy = parcTreeMap_Copy(tree1);
+
+ for (int i = 1; i < 10; i++) {
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ assertFalse(parcTreeMap_Equals(tree1, treeCopy), "Lists are not equal");
+
+ parcTreeMap_Release(&treeCopy);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Copy_Direct)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ for (int i = 1; i < 20; i++) {
+ parcTreeMap_Put(tree1, data->k[i], data->v[i]);
+ }
+
+ PARCTreeMap *treeCopy = parcTreeMap_Copy(tree1);
+
+ assertTrue(parcTreeMap_Equals(tree1, treeCopy), "Lists are not equal");
+
+ parcTreeMap_Release(&treeCopy);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_ValueIterator)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]);
+ }
+
+ PARCIterator *it = parcTreeMap_CreateValueIterator(tree1);
+
+ for (int idx = 1; parcIterator_HasNext(it); ++idx) {
+ _Int *value = (_Int *) parcIterator_Next(it);
+ assertTrue(_int_Equals(value, data->v[idx]), "Expected value %d got %d", data->v[idx]->value, value->value);
+ }
+
+ parcIterator_Release(&it);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_KeyIterator)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]);
+ }
+
+ PARCIterator *it = parcTreeMap_CreateKeyIterator(tree1);
+
+ for (int idx = 1; parcIterator_HasNext(it); ++idx) {
+ _Int *key = (_Int *) parcIterator_Next(it);
+ assertTrue(_int_Equals(key, data->k[idx]),
+ "Expected value %d got %d",
+ data->k[idx]->value,
+ key->value);
+ }
+
+ parcIterator_Release(&it);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Iterator)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]);
+ }
+
+ PARCIterator *it = parcTreeMap_CreateKeyValueIterator(tree1);
+
+ for (int idx = 1; parcIterator_HasNext(it); ++idx) {
+ PARCKeyValue *kv = (PARCKeyValue *) parcIterator_Next(it);
+ assertTrue(_int_Equals((_Int *) parcKeyValue_GetKey(kv), data->k[idx]),
+ "Expected value %d got %d",
+ data->k[idx]->value,
+ ((_Int *) parcKeyValue_GetKey(kv))->value);
+ }
+
+ parcIterator_Release(&it);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_Using_Iterator)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+
+ int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]);
+ }
+
+ PARCIterator *it = parcTreeMap_CreateKeyValueIterator(tree1);
+ for (int idx = 1; parcIterator_HasNext(it); ++idx) {
+ parcIterator_Next(it);
+ parcIterator_Remove(it);
+ }
+ parcIterator_Release(&it);
+
+ assertTrue(parcTreeMap_Size(tree1) == 0, "Expect the tree to be empty after removes.");
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeMap_Remove_Element_Using_Iterator)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCTreeMap *tree1 = data->testMap1;
+ PARCTreeMap *tree2 = data->testMap1;
+
+ int idx1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 15, 13 }; //Missing 11
+
+ for (int i = 0; i < 14; i++) {
+ // Add some elements to the tree
+ parcTreeMap_Put(tree1, data->k[idx1[i]], data->v[idx1[i]]);
+ parcTreeMap_Put(tree2, data->k[idx1[i]], data->v[idx1[i]]);
+ }
+
+ parcTreeMap_Put(tree1, data->k[11], data->v[11]);
+
+
+ PARCIterator *it = parcTreeMap_CreateKeyValueIterator(tree1);
+ for (int idx = 1; parcIterator_HasNext(it); ++idx) {
+ parcIterator_Next(it);
+ if (idx == 11) {
+ parcIterator_Remove(it);
+ }
+ }
+ parcIterator_Release(&it);
+
+ assertTrue(parcTreeMap_Equals(tree1, tree2), "Expect the trees to be equal after remove.");
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ //LONGBOW_RUN_TEST_CASE(Local, PARC_TreeMap_EnsureRemaining_NonEmpty);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Stress)
+{
+ // LongBow could use a command line option to enable/disable tests
+ // See LongBow issue #5
+ if (getenv("LongBowStress")) {
+ LONGBOW_RUN_TEST_CASE(Stress, PARC_TreeMap_ExerciseRandomSeededSmall);
+ LONGBOW_RUN_TEST_CASE(Stress, PARC_TreeMap_ExerciseRandomSeeded);
+ }
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Stress)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Stress)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Stress, PARC_TreeMap_ExerciseRandomSeededSmall)
+{
+ unsigned seed;
+ char *seedString;
+
+ seedString = getenv("RBSeed");
+ if (seedString) {
+ seed = (unsigned) atol(seedString);
+ } else {
+ seed = 4179329122; // known to fail
+ }
+
+ for (int j = 0; j < 1; j++) {
+ // this test case should obtain a seed and number of iterations from a
+ // command line option once LongBow has that feature available
+
+ srandom(seed);
+ PARCTreeMap *tree = parcTreeMap_Create();
+
+ int inserts = 0;
+ int deletes = 0;
+
+ for (int i = 0; i < 100; i++) {
+ intptr_t item = 1 + (random() % 100);
+ int operation = random() % 1000;
+ if (operation < 400) {
+ inserts++;
+ parcTreeMap_Put(tree, (void *) item, (void *) (item << 8));
+ } else {
+ deletes++;
+ parcTreeMap_Remove(tree, (void *) item);
+ }
+ rbCheckTree(tree);
+ }
+
+ parcTreeMap_Release(&tree);
+ }
+}
+
+LONGBOW_TEST_CASE(Stress, PARC_TreeMap_ExerciseRandomSeeded)
+{
+ PARCTreeMap *tree1;
+ unsigned seed;
+ char *seedString;
+
+ // this test case should obtain a seed and number of iterations from a
+ // command line option once LongBow has that feature available
+ seedString = getenv("RBSeed");
+ if (seedString) {
+ seed = (unsigned) atol(seedString);
+ } else {
+ seed = 4179329122; // known to fail
+ }
+
+ srandom(seed);
+
+ tree1 = parcTreeMap_Create();
+
+ int inserts = 0;
+ int deletes = 0;
+
+ for (int i = 0; i < 100000; i++) {
+ intptr_t item = 1 + (random() % 10000);
+ int operation = random() % 1000;
+ if (operation < 400) {
+ inserts++;
+ parcTreeMap_Put(tree1, (void *) item, (void *) (item << 8));
+ } else {
+ deletes++;
+ parcTreeMap_Remove(tree1, (void *) item);
+ }
+ rbCheckTree(tree1);
+ }
+
+ parcTreeMap_Release(&tree1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARC_TreeMap);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_TreeRedBlack.c b/libparc/parc/algol/test/test_parc_TreeRedBlack.c
new file mode 100755
index 00000000..7fb1828a
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_TreeRedBlack.c
@@ -0,0 +1,1461 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <time.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+#include "../parc_TreeRedBlack.c"
+
+
+void *
+keyNewInt(int key)
+{
+ int *newKey = parcMemory_Allocate(sizeof(int));
+ assertNotNull(newKey, "parcMemory_Allocate(%zu) returned NULL", sizeof(int));
+ *newKey = key;
+ return newKey;
+}
+
+void *
+valueNewInt(int value)
+{
+ int *newValue = parcMemory_Allocate(sizeof(int));
+ assertNotNull(newValue, "parcMemory_Allocate(%zu) returned NULL", sizeof(int));
+ *newValue = value;
+ return newValue;
+}
+
+void *
+keyCopy(const void *key)
+{
+ return keyNewInt(*(int *) key);
+}
+
+void *
+valueCopy(const void *value)
+{
+ return valueNewInt(*(int *) value);
+}
+
+void *
+keyNew(char *key)
+{
+ return parcMemory_StringDuplicate(key, strlen(key));
+}
+
+void *
+valueNew(char *value)
+{
+ return parcMemory_StringDuplicate(value, strlen(value));
+}
+
+int
+intComp(const void *key1, const void *key2)
+{
+ if (*(int *) key1 < *(int *) key2) {
+ return -1;
+ }
+ if (*(int *) key1 == *(int *) key2) {
+ return 0;
+ }
+ return 1;
+}
+
+bool
+intEquals(const void *int1, const void *int2)
+{
+ return intComp(int1, int2) == 0;
+}
+
+int
+pointerComp(const void *key1, const void *key2)
+{
+ if (key1 < key2) {
+ return -1;
+ }
+ if (key1 == key2) {
+ return 0;
+ }
+ return 1;
+}
+
+int
+stringComp(const void *key1, const void *key2)
+{
+ // We assume all keys are strings.
+ return strcmp(key1, key2);
+}
+
+void
+keyFree(void **value)
+{
+ parcMemory_Deallocate((void **) value);
+ *value = NULL;
+}
+
+void
+valueFree(void **key)
+{
+ parcMemory_Deallocate((void **) key);
+ *key = NULL;
+}
+
+
+LONGBOW_TEST_RUNNER(PARC_TreeRedBlack)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+ LONGBOW_RUN_TEST_FIXTURE(Stress);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(PARC_TreeRedBlack)
+{
+ int seed = (int) time(NULL);
+ printf("Seed = %u\n", seed);
+ srandom(seed);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(PARC_TreeRedBlack)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_Ordered);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Create);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Ordered);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Insert_OutOfOrder);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Overwrite);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_DestroyTillEmpty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Size_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Size);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Size_Overwrite);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_EmptyTree);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_NonExistent);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_Biggest);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_Smallest);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_FirstKey);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_LastKey);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_FirstKey_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Get_LastKey_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_NonExistent);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_First);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_Last);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_NonExistent);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_WithSuccessorNonRoot);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Remove_LeftChildRightChild);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Keys);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Values);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Func);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_DifferentLength);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Values);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Values_Func);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Keys);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_Copy_Direct);
+ //LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_ExerciseRandom);
+ //LONGBOW_RUN_TEST_CASE(Global, PARC_TreeRedBlack_ExerciseRootFailure);
+}
+
+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
+int
+strComp(const void *s1, const void *s2)
+{
+ return strcmp((char *) s1, (char *) s2);
+}
+
+static
+bool
+strEquals(const void *s1, const void *s2)
+{
+ return strcmp(s1, s2) == 0;
+}
+
+static
+int
+recursiveCheckBlackDepth(const PARCTreeRedBlack *tree, const Node *node)
+{
+ assertNotNull(tree, "Null tree?\n");
+ assertNotNull(node, "Null node?\n");
+ if (node == tree->nil) {
+ return 0;
+ }
+ int right_depth = recursiveCheckBlackDepth(tree, node->right_child);
+ int left_depth = recursiveCheckBlackDepth(tree, node->left_child);
+ assertTrue(right_depth == left_depth, "Wrong depth!!\n");
+ if (_rbNodeColor(node) == BLACK) {
+ return right_depth + 1;
+ }
+ return right_depth;
+}
+
+static
+void
+rbCheckTree(const PARCTreeRedBlack *tree)
+{
+ assertNotNull(tree, "Tree can't be NULL");
+ //printf("--- TREE ---\n");
+ if (tree->size > 0) {
+ //_rbNodeRecursiveRun((PARCTreeRedBlack *)tree,tree->root,rbCheckNode,(void *)tree);
+ recursiveCheckBlackDepth(tree, tree->root);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_Ordered)
+{
+ char *insertList[16] = {
+ "01",
+ "02",
+ "03",
+ "04",
+ "05",
+ "06",
+ "07",
+ "08",
+ "09",
+ "10",
+ "11",
+ "12",
+ "13",
+ "14",
+ "15",
+ "16"
+ };
+
+ PARCTreeRedBlack *tree1;
+
+ tree1 = parcTreeRedBlack_Create(strComp, NULL, NULL, strEquals, NULL, NULL);
+
+ for (int i = 0; i < 16; i++) {
+ parcTreeRedBlack_Insert(tree1, insertList[i], insertList[i]);
+ }
+
+ for (int i = 0; i < 14; i++) {
+ //rbPrintTreeString(tree1);
+ void *data = parcTreeRedBlack_Remove(tree1, insertList[i]);
+ assertNotNull(data, "Data is null!");
+ }
+
+ parcTreeRedBlack_Destroy(&tree1);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Create)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(stringComp, NULL, NULL, NULL, NULL, NULL);
+
+ parcTreeRedBlack_Destroy(&tree);
+
+ tree = parcTreeRedBlack_Create(stringComp, keyFree, NULL, NULL, valueFree, NULL);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Destroy)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(stringComp, keyFree, NULL, NULL, valueFree, NULL);
+
+ void *value1 = valueNew("value 1");
+ void *key1 = keyNew("1");
+ void *value2 = valueNew("value 2");
+ void *key2 = keyNew("2");
+ void *value3 = valueNew("value 3");
+ void *key3 = keyNew("3");
+
+ parcTreeRedBlack_Insert(tree, key1, value1);
+ parcTreeRedBlack_Insert(tree, key2, value2);
+ parcTreeRedBlack_Insert(tree, key3, value3);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Overwrite)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(stringComp, keyFree, NULL, NULL, valueFree, NULL);
+
+ parcTreeRedBlack_Insert(tree, keyNew("1"), valueNew("v1"));
+ parcTreeRedBlack_Insert(tree, keyNew("2"), valueNew("v2"));
+ parcTreeRedBlack_Insert(tree, keyNew("3"), valueNew("v3"));
+ parcTreeRedBlack_Insert(tree, keyNew("3"), valueNew("v4"));
+ parcTreeRedBlack_Insert(tree, keyNew("3"), valueNew("v5"));
+
+ assertTrue(3 == parcTreeRedBlack_Size(tree), "Wrong size of tree should stay at 3");
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Insert_Ordered)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ parcTreeRedBlack_Insert(tree, (void *) 1, (void *) 1001);
+ parcTreeRedBlack_Insert(tree, (void *) 2, (void *) 1002);
+ parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1003);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Insert_OutOfOrder)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ parcTreeRedBlack_Insert(tree, (void *) 4, (void *) 1004);
+ parcTreeRedBlack_Insert(tree, (void *) 2, (void *) 1002);
+ parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1003);
+ parcTreeRedBlack_Insert(tree, (void *) 1, (void *) 1001);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Size_Empty)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ assertTrue(0 == parcTreeRedBlack_Size(tree), "Wrong size of tree - empty, start");
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Size)
+{
+ PARCTreeRedBlack *tree;
+ size_t size;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ parcTreeRedBlack_Insert(tree, (void *) 4, (void *) 1004);
+ parcTreeRedBlack_Insert(tree, (void *) 2, (void *) 1002);
+ parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1003);
+
+ assertTrue(3 == parcTreeRedBlack_Size(tree), "Wrong size of tree after add 3");
+
+ parcTreeRedBlack_Insert(tree, (void *) 1, (void *) 1001);
+
+ assertTrue(4 == parcTreeRedBlack_Size(tree), "Wrong size of tree after add 1 more");
+
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 2);
+
+ size = parcTreeRedBlack_Size(tree);
+
+ assertTrue(3 == size, "Wrong size of tree after 1 delete (%zu instead of 3)", size);
+
+ parcTreeRedBlack_Insert(tree, (void *) 7, (void *) 1007);
+
+ assertTrue(4 == parcTreeRedBlack_Size(tree), "Wrong size of tree after add 1 more");
+
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 3);
+ assertTrue(3 == parcTreeRedBlack_Size(tree), "Wrong size of tree after del 1 more - 3");
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_DestroyTillEmpty)
+{
+ PARCTreeRedBlack *tree;
+ size_t size;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ parcTreeRedBlack_Insert(tree, (void *) 4, (void *) 1004);
+ parcTreeRedBlack_Insert(tree, (void *) 2, (void *) 1002);
+ parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1003);
+ parcTreeRedBlack_Insert(tree, (void *) 1, (void *) 1001);
+ parcTreeRedBlack_Insert(tree, (void *) 5, (void *) 1001);
+ parcTreeRedBlack_Insert(tree, (void *) 7, (void *) 1001);
+ parcTreeRedBlack_Insert(tree, (void *) 6, (void *) 1001);
+
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 3);
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 1);
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 4);
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 2);
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 6);
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 5);
+ parcTreeRedBlack_RemoveAndDestroy(tree, (void *) 7);
+
+ size = parcTreeRedBlack_Size(tree);
+
+ assertTrue(0 == size, "Wrong size of tree - empty (got %zu)", size);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Size_Overwrite)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ parcTreeRedBlack_Insert(tree, (void *) 4, (void *) 1004);
+ parcTreeRedBlack_Insert(tree, (void *) 2, (void *) 1002);
+ parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1003);
+
+ // Size is 3 here, we'll insert the same number now..
+
+ parcTreeRedBlack_Insert(tree, (void *) 3, (void *) 1033);
+
+ assertTrue(3 == parcTreeRedBlack_Size(tree), "Wrong size of tree after overwrite");
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_EmptyTree)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ void *value = parcTreeRedBlack_Get(tree, (void *) 1);
+
+ assertTrue(NULL == value, "Object did not exist, must return NULL");
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_NonExistent)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+
+ void *value = parcTreeRedBlack_Get(tree, (void *) 100);
+
+ assertTrue(NULL == value, "Object did not exist, must return NULL");
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_First)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < 4; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+
+ void *value = parcTreeRedBlack_Get(tree, (void *) 1);
+
+ assertTrue((1 << 8) == (long) value, "Wrong value, got %ld", (long) value);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+
+ void *value = parcTreeRedBlack_Get(tree, (void *) 4);
+
+ assertTrue((4 << 8) == (long) value, "Wrong value, got %ld", (long) value);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_Last)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+
+ void *value = parcTreeRedBlack_Get(tree, (void *) 9);
+
+ assertTrue((9 << 8) == (long) value, "Wrong value, got %ld", (long) value);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_Smallest)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+
+
+ void *value = parcTreeRedBlack_Get(tree, (void *) 1);
+
+ assertTrue((1 << 8) == (long) value, "Wrong value, got %ld", (long) value);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_Biggest)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+
+
+ void *value = parcTreeRedBlack_Get(tree, (void *) 39);
+
+ assertTrue((39 << 8) == (long) value, "Wrong value, got %ld", (long) value);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_FirstKey)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+
+ void *key = parcTreeRedBlack_FirstKey(tree);
+
+ assertTrue(1 == (long) key, "Wrong value, got %ld", (long) key);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_FirstKey_Empty)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ void *key = parcTreeRedBlack_FirstKey(tree);
+
+ assertNull(key, "Should get NULL on empty tree");
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_LastKey_Empty)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ void *key = parcTreeRedBlack_LastKey(tree);
+
+ assertNull(key, "Should get NULL on empty tree");
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Get_LastKey)
+{
+ PARCTreeRedBlack *tree;
+
+ tree = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree, (void *) i, (void *) (i << 8));
+ }
+
+ void *key = parcTreeRedBlack_LastKey(tree);
+
+ assertTrue(39 == (long) key, "Wrong value, got %ld", (long) key);
+
+ parcTreeRedBlack_Destroy(&tree);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_First)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL);
+ tree2 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL);
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+
+ parcTreeRedBlack_Insert(tree1, keyNewInt(1), valueNewInt(1 << 8));
+
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+
+ int searchKey = 1;
+
+ void *data = parcTreeRedBlack_Remove(tree1, &searchKey);
+
+ valueFree(&data);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL);
+ tree2 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL);
+
+ for (int i = 31; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+
+ parcTreeRedBlack_Insert(tree1, keyNewInt(30), valueNewInt(31 << 8));
+
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+
+ int searchKey = 30;
+
+ void *data = parcTreeRedBlack_Remove(tree1, &searchKey);
+
+ valueFree(&data);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_Last)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL);
+ tree2 = parcTreeRedBlack_Create(intComp, keyFree, NULL, intEquals, valueFree, NULL);
+
+ for (int i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+ parcTreeRedBlack_Insert(tree1, keyNewInt(100), valueNewInt(100 << 8));
+ for (int i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+ for (int i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, keyNewInt(i), valueNewInt(i << 8));
+ parcTreeRedBlack_Insert(tree2, keyNewInt(i), valueNewInt(i << 8));
+ }
+
+ int searchKey = 100;
+
+ void *data = parcTreeRedBlack_Remove(tree1, &searchKey);
+
+ valueFree(&data);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_First)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+
+ parcTreeRedBlack_Insert(tree1, (void *) 1, (void *) (1 << 8));
+
+ for (long i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 1);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 31; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+
+ parcTreeRedBlack_Insert(tree1, (void *) 30, (void *) (30 << 8));
+
+ for (long i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 30);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_NonExistent)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+
+ void *element = parcTreeRedBlack_Remove(tree1, (void *) 100);
+
+ assertNull(element, "Return value must be NULL on non existing element");
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_NonExistent)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 100);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_WithSuccessorNonRoot)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ long insert1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+ long insert2[13] = { 8, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) insert1[i], (void *) (insert1[i] << 8));
+ }
+
+ for (int i = 0; i < 13; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree2, (void *) insert2[i], (void *) (insert2[i] << 8));
+ }
+
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 4);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 12);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Remove_LeftChildRightChild)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ long insert1[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+ long insert2[15] = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) insert1[i], (void *) (insert1[i] << 8));
+ }
+
+ for (int i = 0; i < 15; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree2, (void *) insert2[i], (void *) (insert2[i] << 8));
+ }
+
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 13);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 7);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 14);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 6);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 15);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 12);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 11);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 10);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 9);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 8);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 5);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 4);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 3);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 2);
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 1);
+
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 1);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 2);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 3);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 4);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 5);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 6);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 7);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 8);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 9);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 10);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 11);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 12);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 13);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 14);
+ parcTreeRedBlack_RemoveAndDestroy(tree2, (void *) 15);
+
+ //assertTrue(parcTreeRedBlack_Equals(tree1,tree2),"Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_RemoveAndDestroy_Last)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 30; i < 40; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+ parcTreeRedBlack_Insert(tree1, (void *) 100, (void *) (100 << 8));
+ for (long i = 2; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 20; i < 30; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2, (void *) i, (void *) (i << 8));
+ }
+
+ parcTreeRedBlack_RemoveAndDestroy(tree1, (void *) 100);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Trees dont match after remove");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Keys)
+{
+ PARCTreeRedBlack *tree1;
+ PARCArrayList *list;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ list = parcArrayList_Create(NULL);
+
+ // Insert in tree out of order
+ for (long i = 10; i < 20; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ }
+
+ // Insert in list in order
+ for (long i = 1; i < 20; i++) {
+ // Add some elements to the tree
+ parcArrayList_Add(list, (void *) i);
+ }
+
+ PARCArrayList *keys = parcTreeRedBlack_Keys(tree1);
+
+ assertTrue(parcArrayList_Equals(list, keys), "Key list doesnt' match");
+
+ parcArrayList_Destroy(&keys);
+ parcArrayList_Destroy(&list);
+ parcTreeRedBlack_Destroy(&tree1);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Values)
+{
+ PARCTreeRedBlack *tree1;
+ PARCArrayList *list;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ list = parcArrayList_Create(NULL);
+
+ // Insert in tree out of order
+ for (long i = 10; i < 20; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ }
+ for (long i = 1; i < 10; i++) {
+ // Add some elements to the tree
+ parcTreeRedBlack_Insert(tree1, (void *) i, (void *) (i << 8));
+ }
+
+ // Insert in list in order
+ for (long i = 1; i < 20; i++) {
+ // Add some elements to the tree
+ parcArrayList_Add(list, (void *) (i << 8));
+ }
+
+ PARCArrayList *values = parcTreeRedBlack_Values(tree1);
+
+ assertTrue(parcArrayList_Equals(list, values), "Key list doesnt' match");
+
+ parcArrayList_Destroy(&values);
+ parcArrayList_Destroy(&list);
+ parcTreeRedBlack_Destroy(&tree1);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Empty)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Empty lists are not equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_DifferentLength)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ int compareInserts = 100;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < compareInserts; i++) {
+ parcTreeRedBlack_Insert(tree1,
+ (void *) i,
+ (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2,
+ (void *) (compareInserts - i),
+ (void *) ((compareInserts - i) << 8));
+ }
+ parcTreeRedBlack_Insert(tree2, (void *) (1000), (void *) ((12304) << 8));
+
+ assertFalse(parcTreeRedBlack_Equals(tree1, tree2), "Lists are equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Values)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ int compareInserts = 100;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < compareInserts; i++) {
+ parcTreeRedBlack_Insert(tree1,
+ (void *) i,
+ (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2,
+ (void *) (compareInserts - i),
+ (void *) ((compareInserts + i) << 8));
+ }
+
+ assertFalse(parcTreeRedBlack_Equals(tree1, tree2), "Lists are equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Values_Func)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ int compareInserts = 100;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, keyFree, keyCopy, intEquals, valueFree, valueCopy);
+ tree2 = parcTreeRedBlack_Create(pointerComp, keyFree, keyCopy, intEquals, valueFree, valueCopy);
+
+ for (int i = 1; i < compareInserts; i++) {
+ parcTreeRedBlack_Insert(tree1,
+ keyNewInt(i),
+ valueNewInt(i + 1000));
+ parcTreeRedBlack_Insert(tree2,
+ keyNewInt(i),
+ valueNewInt(i + 2000));
+ }
+
+ assertFalse(parcTreeRedBlack_Equals(tree1, tree2), "Lists are equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Not_Keys)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ int compareInserts = 100;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < compareInserts; i++) {
+ parcTreeRedBlack_Insert(tree1,
+ (void *) i,
+ (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2,
+ (void *) (compareInserts + i),
+ (void *) ((compareInserts - i) << 8));
+ }
+
+ assertFalse(parcTreeRedBlack_Equals(tree1, tree2), "Lists are equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ int compareInserts = 100;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+ tree2 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < compareInserts; i++) {
+ parcTreeRedBlack_Insert(tree1,
+ (void *) i,
+ (void *) (i << 8));
+ parcTreeRedBlack_Insert(tree2,
+ (void *) (compareInserts - i),
+ (void *) ((compareInserts - i) << 8));
+ }
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Lists are not equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Equals_Func)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ int compareInserts = 100;
+
+ tree1 = parcTreeRedBlack_Create(intComp, keyFree, keyCopy, intEquals, valueFree, valueCopy);
+ tree2 = parcTreeRedBlack_Create(intComp, keyFree, keyCopy, intEquals, valueFree, valueCopy);
+
+ for (int i = 1; i < compareInserts; i++) {
+ parcTreeRedBlack_Insert(tree1,
+ keyNewInt(i),
+ valueNewInt(i + 1000));
+ parcTreeRedBlack_Insert(tree2,
+ keyNewInt(i),
+ valueNewInt(i + 1000));
+ }
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Lists are not equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Copy)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ int compareInserts = 20;
+
+ tree1 = parcTreeRedBlack_Create(intComp, keyFree, keyCopy, intEquals, valueFree, valueCopy);
+
+ for (int i = 1; i < compareInserts; i++) {
+ void *key = keyNewInt(i);
+ void *value = valueNewInt(i + 1000);
+ //value = (void *) &((*(int*)value) + 100);
+ parcTreeRedBlack_Insert(tree1, key, value);
+ }
+
+ tree2 = parcTreeRedBlack_Copy(tree1);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Lists are not equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_CASE(Global, PARC_TreeRedBlack_Copy_Direct)
+{
+ PARCTreeRedBlack *tree1;
+ PARCTreeRedBlack *tree2;
+
+ int compareInserts = 20;
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ for (long i = 1; i < compareInserts; i++) {
+ parcTreeRedBlack_Insert(tree1,
+ (void *) i,
+ (void *) (i << 8));
+ }
+
+ tree2 = parcTreeRedBlack_Copy(tree1);
+
+ assertTrue(parcTreeRedBlack_Equals(tree1, tree2), "Lists are not equal");
+
+ parcTreeRedBlack_Destroy(&tree1);
+ parcTreeRedBlack_Destroy(&tree2);
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ //LONGBOW_RUN_TEST_CASE(Local, PARC_TreeRedBlack_EnsureRemaining_NonEmpty);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Stress)
+{
+ // LongBow could use a command line option to enable/disable tests
+ // See LongBow issue #5
+ if (getenv("LongBowStress")) {
+ LONGBOW_RUN_TEST_CASE(Stress, PARC_TreeRedBlack_ExerciseRandomSeededSmall);
+ LONGBOW_RUN_TEST_CASE(Stress, PARC_TreeRedBlack_ExerciseRandomSeeded);
+ }
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Stress)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Stress)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Stress, PARC_TreeRedBlack_ExerciseRandomSeededSmall)
+{
+ PARCTreeRedBlack *tree1;
+ unsigned seed;
+ char *seedString;
+
+ seedString = getenv("RBSeed");
+ if (seedString) {
+ seed = (unsigned) atol(seedString);
+ } else {
+ seed = 4179329122; // known to fail
+ }
+
+ for (int j = 0; j < 1; j++) {
+ // this test case should obtain a seed and number of iterations from a
+ // command line option once LongBow has that feature available
+
+ printf("Random seed %u\n", seed);
+
+ srandom(seed);
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ int inserts = 0;
+ int deletes = 0;
+
+ for (int i = 0; i < 100; i++) {
+ intptr_t item = 1 + (random() % 100);
+ int operation = random() % 1000;
+ if (operation < 400) {
+ inserts++;
+ parcTreeRedBlack_Insert(tree1, (void *) item, (void *) (item << 8));
+ } else {
+ deletes++;
+ parcTreeRedBlack_Remove(tree1, (void *) item);
+ }
+ rbCheckTree(tree1);
+ }
+
+ parcTreeRedBlack_Destroy(&tree1);
+ }
+}
+
+LONGBOW_TEST_CASE(Stress, PARC_TreeRedBlack_ExerciseRandomSeeded)
+{
+ PARCTreeRedBlack *tree1;
+ unsigned seed;
+ char *seedString;
+
+ // this test case should obtain a seed and number of iterations from a
+ // command line option once LongBow has that feature available
+ seedString = getenv("RBSeed");
+ if (seedString) {
+ seed = (unsigned) atol(seedString);
+ } else {
+ seed = 4179329122; // known to fail
+ }
+ printf("Random seed %u\n", seed);
+
+ srandom(seed);
+
+ tree1 = parcTreeRedBlack_Create(pointerComp, NULL, NULL, NULL, NULL, NULL);
+
+ int inserts = 0;
+ int deletes = 0;
+
+ for (int i = 0; i < 100000; i++) {
+ intptr_t item = 1 + (random() % 10000);
+ int operation = random() % 1000;
+ if (operation < 400) {
+ inserts++;
+ parcTreeRedBlack_Insert(tree1, (void *) item, (void *) (item << 8));
+ } else {
+ deletes++;
+ parcTreeRedBlack_Remove(tree1, (void *) item);
+ }
+ rbCheckTree(tree1);
+ }
+
+ parcTreeRedBlack_Destroy(&tree1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARC_TreeRedBlack);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_URI.c b/libparc/parc/algol/test/test_parc_URI.c
new file mode 100644
index 00000000..5050deb3
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_URI.c
@@ -0,0 +1,642 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ *
+ */
+#include "../parc_URI.c"
+#include <LongBow/unit-test.h>
+
+#include <stdint.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <parc/algol/parc_Hash.h>
+
+#include "_test_parc_URI.h"
+
+LONGBOW_TEST_RUNNER(parcURI)
+{
+ LONGBOW_RUN_TEST_FIXTURE(parcURI);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parcURI)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(parcURI)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Tests leak memory by %d allocations\n", outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(parcURI)
+{
+ LONGBOW_RUN_TEST_CASE(parcURI, parseScheme);
+ LONGBOW_RUN_TEST_CASE(parcURI, parseScheme_Only);
+ LONGBOW_RUN_TEST_CASE(parcURI, parseScheme_BadScheme);
+ LONGBOW_RUN_TEST_CASE(parcURI, parseScheme_EmptyScheme);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parseAuthority);
+ LONGBOW_RUN_TEST_CASE(parcURI, parseAuthority_NoAuthority);
+ LONGBOW_RUN_TEST_CASE(parcURI, parseAuthority_NoPath);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Acquire);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_AuthorityEquals_SamePointer);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_AuthorityEquals_NullPointers);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_QueryEquals_SamePointer);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_QueryEquals_NullPointers);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_FragmentEquals_SamePointer);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_FragmentEquals_NullPointers);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SchemeEquals_SamePointer);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SchemeEquals_NullPointers);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Parse);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Parse_NoScheme);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Parse_SchemeOnly);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetScheme);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetScheme_Reset);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetScheme_Resetting);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetFragment);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetFragment_Reset);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetFragment_Resetting);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetQuery);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetQuery_Reset);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetQuery_Resetting);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetAuthority);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetAuthority_Reset);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_SetAuthority_Resetting);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Equals_Contract);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_GetPath);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_GetQuery);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_GetFragment);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_Copy);
+ LONGBOW_RUN_TEST_CASE(parcURI, parcURI_ToString_Full);
+
+ LONGBOW_RUN_TEST_CASE(parcURI, PARCURI_ToString_SchemeOnly);
+ LONGBOW_RUN_TEST_CASE(parcURI, PARCURI_ToString_NoAuthority);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(parcURI)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(parcURI)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_Acquire)
+{
+ char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+
+ PARCURI *uri = parcURI_Parse(uriString);
+
+ PARCURI *handle = parcURI_Acquire(uri);
+
+ assertTrue(parcURI_Equals(uri, handle), "Expected URI and acquired handle to be equal");
+
+ parcURI_Release(&handle);
+ parcURI_Release(&uri);
+ parcMemory_Deallocate((void **) &uriString);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_AuthorityEquals_SamePointer)
+{
+ char *authority = "authority@auth";
+ assertTrue(_parcURI_AuthorityEquals(authority, authority),
+ "Expected authorities to be equal since they're the same pointers: %p - %p",
+ (void *) authority, (void *) authority);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_AuthorityEquals_NullPointers)
+{
+ char *authority = "authority@auth";
+ assertFalse(_parcURI_AuthorityEquals(NULL, authority), "Expected authorities to not be equal since one is NULL");
+ assertFalse(_parcURI_AuthorityEquals(authority, NULL), "Expected authorities to not be equal since one is NULL");
+ assertTrue(_parcURI_AuthorityEquals(NULL, NULL), "Expected authorities to be equal since both are NULL");
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_QueryEquals_SamePointer)
+{
+ char *query = "query";
+ assertTrue(_parcURI_QueryEquals(query, query),
+ "Expected queries to be equal since they're the same pointers: %p - %p",
+ (void *) query, (void *) query);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_QueryEquals_NullPointers)
+{
+ char *query = "query";
+ assertFalse(_parcURI_QueryEquals(NULL, query), "Expected queries to not be equal since one is NULL");
+ assertFalse(_parcURI_QueryEquals(query, NULL), "Expected queries to not be equal since one is NULL");
+ assertTrue(_parcURI_QueryEquals(NULL, NULL), "Expected queries to be equal since both are NULL");
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_FragmentEquals_SamePointer)
+{
+ char *fragment = "fragment";
+ assertTrue(_parcURI_FragmentEquals(fragment, fragment),
+ "Expected fragments to be equal since they're the same pointers: %p - %p",
+ (void *) fragment, (void *) fragment);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_FragmentEquals_NullPointers)
+{
+ char *fragment = "fragment";
+ assertFalse(_parcURI_FragmentEquals(NULL, fragment), "Expected fragments to not be equal since one is NULL");
+ assertFalse(_parcURI_FragmentEquals(fragment, NULL), "Expected fragments to not be equal since one is NULL");
+ assertTrue(_parcURI_FragmentEquals(NULL, NULL), "Expected fragments to be equal since both are NULL");
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SchemeEquals_SamePointer)
+{
+ char *scheme = "scheme";
+ assertTrue(_parcURI_SchemeEquals(scheme, scheme),
+ "Expected schemes to be equal since they're the same pointers: %p - %p",
+ (void *) scheme, (void *) scheme);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SchemeEquals_NullPointers)
+{
+ char *scheme = "scheme";
+ assertFalse(_parcURI_SchemeEquals(NULL, scheme), "Expected schemes to not be equal since one is NULL");
+ assertFalse(_parcURI_SchemeEquals(scheme, NULL), "Expected schemes to not be equal since one is NULL");
+ assertTrue(_parcURI_SchemeEquals(NULL, NULL), "Expected schemes to be equal since both are NULL");
+}
+
+LONGBOW_TEST_CASE(parcURI, parseScheme_EmptyScheme)
+{
+ const char *pointer;
+ char *actual = _parseScheme(":", &pointer); // empty string
+ assertNull(actual, "Parsed scheme should be NULL since the input string was empty.");
+ actual = _parseScheme("", &pointer); // empty string
+ assertNull(actual, "Parsed scheme should be NULL since the input string was empty.");
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_Parse)
+{
+ char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+
+ PARCURI *uri = parcURI_Parse(uriString);
+ assertNotNull(uri, "Expected non-null result for '%s'", uriString);
+
+ memset(uriString, 0, strlen(uriString));
+
+ assertTrue(strcmp(URI_SCHEME, parcURI_GetScheme(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_SCHEME, parcURI_GetScheme(uri));
+ assertTrue(strcmp(URI_AUTHORITY, parcURI_GetAuthority(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_AUTHORITY, parcURI_GetAuthority(uri));
+ assertTrue(strcmp(URI_QUERY, parcURI_GetQuery(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_QUERY, parcURI_GetQuery(uri));
+ assertTrue(strcmp(URI_FRAGMENT, parcURI_GetFragment(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_FRAGMENT, parcURI_GetFragment(uri));
+
+ parcMemory_Deallocate((void **) &uriString);
+
+ parcURI_Release(&uri);
+ assertNull(uri, "Expected parcURI_Release to null the pointer.");
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_Parse_NoScheme)
+{
+ char *uriString = "/" URI_PATH_SEGMENT;
+
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+
+ PARCURI *uri = parcURI_Parse(uriString);
+ assertNull(uri,
+ "Expected null result for '%s'", uriString);
+ parcMemory_Deallocate((void **) &uriString);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_Parse_SchemeOnly)
+{
+ char *uriString = URI_SCHEME ":";
+
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+
+ PARCURI *uri = parcURI_Parse(uriString);
+ assertNotNull(uri,
+ "Expected non-null result for '%s'", uriString);
+
+ memset(uriString, 0, strlen(uriString));
+
+ assertTrue(strcmp(URI_SCHEME, parcURI_GetScheme(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_SCHEME, parcURI_GetScheme(uri));
+ assertNull(parcURI_GetAuthority(uri),
+ "Expected NULL, actual '%s'", parcURI_GetAuthority(uri));
+ assertNull(parcURI_GetQuery(uri),
+ "Expected NULL, actual '%s'", parcURI_GetQuery(uri));
+ assertNull(parcURI_GetFragment(uri),
+ "Expected NULL, actual '%s'", parcURI_GetFragment(uri));
+
+ parcMemory_Deallocate((void **) &uriString);
+ parcURI_Release(&uri);
+ assertNull(uri,
+ "Expected parcURI_Release to null the pointer.");
+}
+
+LONGBOW_TEST_CASE(parcURI, parseScheme)
+{
+ const char *pointer;
+ char *actual = _parseScheme(URI_FULL, &pointer);
+ assertTrue(strcmp(URI_SCHEME, actual) == 0,
+ "Expected '%s' actual '%s'", URI_SCHEME, actual);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(parcURI, parseScheme_Only)
+{
+ const char *pointer;
+ char *actual = _parseScheme(URI_SCHEME ":", &pointer);
+ assertTrue(strcmp(URI_SCHEME, actual) == 0,
+ "Expected '%s' actual '%s'", URI_SCHEME, actual);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(parcURI, parseScheme_BadScheme)
+{
+ const char *pointer;
+ char *actual = _parseScheme("", &pointer);
+ assertNull(actual,
+ "Expected NULL actual '%s'", actual);
+}
+
+LONGBOW_TEST_CASE(parcURI, PARCURI_GetAuthority)
+{
+ PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ const char *actual = parcURI_GetAuthority(uri);
+ assertTrue(strcmp(TEST_URI_AUTHORITY, actual) == 0,
+ "Expected '%s' actual '%s'", URI_AUTHORITY, actual);
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_GetQuery)
+{
+ PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ const char *actual = parcURI_GetQuery(uri);
+ assertTrue(strcmp(URI_QUERY, actual) == 0,
+ "Expected '%s' actual '%s'", URI_FRAGMENT, actual);
+
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_GetFragment)
+{
+ PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ const char *actual = parcURI_GetFragment(uri);
+ assertTrue(strcmp(URI_FRAGMENT, actual) == 0,
+ "Expected '%s' actual '%s'", URI_FRAGMENT, actual);
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_GetPath)
+{
+ char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ PARCURI *uri = parcURI_Parse(uriString);
+ PARCURIPath *actual = parcURI_GetPath(uri);
+
+ char *string = parcURIPath_ToString(actual);
+
+ char *expected = URI_PATH_SEGMENT "/" URI_PATH_SEGMENT;
+ assertTrue(strcmp(expected, string) == 0, "Expected '%s' actual '%s'", expected, string);
+
+ parcMemory_Deallocate((void **) &string);
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_Copy)
+{
+ PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ PARCURI *uri2 = parcURI_Copy(uri);
+
+ char *expected = parcURI_ToString(uri);
+ char *actual = parcURI_ToString(uri2);
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &expected);
+ parcMemory_Deallocate((void **) &actual);
+ parcURI_Release(&uri);
+ parcURI_Release(&uri2);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_Equals_Contract)
+{
+ PARCURI *x = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ PARCURI *y = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ PARCURI *z = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ PARCURI *u = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "?" URI_QUERY);
+
+ parcObjectTesting_AssertEqualsFunction(parcURI_Equals, x, y, z, u);
+
+ parcURI_Release(&x);
+ parcURI_Release(&y);
+ parcURI_Release(&z);
+ parcURI_Release(&u);
+}
+
+LONGBOW_TEST_CASE(parcURI, PARCURI_GetScheme)
+{
+ PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ const char *actual = parcURI_GetScheme(uri);
+ assertTrue(strcmp(TEST_URI_SCHEME, actual) == 0,
+ "Expected '%s' actual '%s'", TEST_URI_SCHEME, actual);
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, PARCURI_Parse)
+{
+ PARCURI *uri = parcURI_Parse(URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT);
+ assertNotNull(uri,
+ "Expected a non-null result.");
+
+ assertTrue(strcmp(URI_SCHEME, parcURI_GetScheme(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_SCHEME, parcURI_GetScheme(uri));
+ assertTrue(strcmp(URI_AUTHORITY, parcURI_GetAuthority(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_AUTHORITY, parcURI_GetAuthority(uri));
+ assertTrue(strcmp(URI_QUERY, parcURI_GetQuery(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_QUERY, parcURI_GetQuery(uri));
+ assertTrue(strcmp(URI_FRAGMENT, parcURI_GetFragment(uri)) == 0,
+ "Expected '%s', actual '%s'", URI_FRAGMENT, parcURI_GetFragment(uri));
+
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_ToString_Full)
+{
+ char *expected = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+
+ PARCURI *uri = parcURI_Parse(expected);
+ char *actual = parcURI_ToString(uri);
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ parcMemory_Deallocate((void **) &actual);
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, PARCURI_ToString_SchemeOnly)
+{
+ char *expected = URI_SCHEME ":" "/";
+ PARCURI *uri = parcURI_Parse(expected);
+ char *actual = parcURI_ToString(uri);
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ parcURI_Release(&uri);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(parcURI, PARCURI_ToString_NoAuthority)
+{
+ char *expected = URI_SCHEME ":" "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ PARCURI *uri = parcURI_Parse(expected);
+ char *actual = parcURI_ToString(uri);
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+
+ parcURI_Release(&uri);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(parcURI, parseAuthority)
+{
+ char *authority = "//" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT;
+ char *expected = URI_AUTHORITY;
+
+ const char *pointer;
+ char *actual = _parseAuthority(authority, &pointer);
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", expected, actual);
+ assertTrue(*pointer == '/',
+ "Expected '/' actual '%c'", *pointer);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(parcURI, parseAuthority_NoAuthority)
+{
+ char *string = "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT;
+
+ const char *pointer;
+ char *actual = _parseAuthority(string, &pointer);
+ assertTrue(actual == NULL,
+ "Expected NULL actual '%s'", actual);
+ assertTrue(*pointer == '/',
+ "Expected '/' actual '%c'", *pointer);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetScheme)
+{
+ char *scheme = "scheme";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetScheme(uri, scheme);
+
+ assertTrue(strcmp(scheme, parcURI_GetScheme(uri)) == 0,
+ "Expected %s actual %s", scheme, parcURI_GetScheme(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetScheme_Resetting)
+{
+ char *scheme = "scheme";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetScheme(uri, scheme);
+ _parcURI_SetScheme(uri, scheme);
+
+ assertTrue(strcmp(scheme, parcURI_GetScheme(uri)) == 0,
+ "Expected %s actual %s", scheme, parcURI_GetScheme(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetScheme_Reset)
+{
+ char *scheme = "scheme";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetScheme(uri, scheme);
+ _parcURI_SetScheme(uri, NULL);
+
+ assertNull(parcURI_GetScheme(uri),
+ "Expected NULL actual %s", parcURI_GetScheme(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetFragment)
+{
+ char *fragment = "fragment";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetFragment(uri, fragment);
+
+ assertTrue(strcmp(fragment, parcURI_GetFragment(uri)) == 0,
+ "Expected %s actual %s", fragment, parcURI_GetFragment(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetFragment_Resetting)
+{
+ char *fragment = "fragment";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetFragment(uri, fragment);
+ _parcURI_SetFragment(uri, fragment);
+
+ assertTrue(strcmp(fragment, parcURI_GetFragment(uri)) == 0,
+ "Expected %s actual %s", fragment, parcURI_GetFragment(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetFragment_Reset)
+{
+ char *fragment = "query";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetFragment(uri, fragment);
+ _parcURI_SetFragment(uri, NULL);
+
+ assertNull(parcURI_GetFragment(uri),
+ "Expected NULL actual %s", parcURI_GetFragment(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetQuery)
+{
+ char *query = "query";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetQuery(uri, query);
+
+ assertTrue(strcmp(query, parcURI_GetQuery(uri)) == 0,
+ "Expected %s actual %s", query, parcURI_GetQuery(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetQuery_Resetting)
+{
+ char *query = "query";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetQuery(uri, query);
+ _parcURI_SetQuery(uri, query);
+
+ assertTrue(strcmp(query, parcURI_GetQuery(uri)) == 0,
+ "Expected %s actual %s", query, parcURI_GetQuery(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetQuery_Reset)
+{
+ char *query = "query";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetQuery(uri, query);
+ _parcURI_SetQuery(uri, NULL);
+
+ assertNull(parcURI_GetQuery(uri),
+ "Expected NULL actual %s", parcURI_GetQuery(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetAuthority)
+{
+ char *authority = "authority@auth";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetAuthority(uri, authority);
+
+ assertTrue(strcmp(authority, parcURI_GetAuthority(uri)) == 0,
+ "Expected %s actual %s", authority, parcURI_GetAuthority(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetAuthority_Resetting)
+{
+ char *authority = "query";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetAuthority(uri, authority);
+ _parcURI_SetAuthority(uri, authority);
+
+ assertTrue(strcmp(authority, parcURI_GetAuthority(uri)) == 0,
+ "Expected %s actual %s", authority, parcURI_GetAuthority(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parcURI_SetAuthority_Reset)
+{
+ char *query = "query";
+ PARCURI *uri = parcURI_Create();
+ _parcURI_SetAuthority(uri, query);
+ _parcURI_SetAuthority(uri, NULL);
+
+ assertNull(parcURI_GetAuthority(uri),
+ "Expected NULL actual %s", parcURI_GetAuthority(uri));
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURI, parseAuthority_NoPath)
+{
+ char *authority = "//" URI_AUTHORITY;
+ char *expected = URI_AUTHORITY;
+
+ const char *pointer;
+ char *actual = _parseAuthority(authority, &pointer);
+
+ assertTrue(strcmp(expected, actual) == 0,
+ "Expected '%s' actual '%s'", authority, actual);
+ assertTrue(*pointer == 0,
+ "Expected null actual '%c'", *pointer);
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(parcURI, parseFragment)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(parcURI, parsePath)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(parcURI, parseQuery)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcURI);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(status);
+}
diff --git a/libparc/parc/algol/test/test_parc_URIAuthority.c b/libparc/parc/algol/test/test_parc_URIAuthority.c
new file mode 100644
index 00000000..e6d8196a
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_URIAuthority.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 "../parc_URIAuthority.c"
+#include <stdint.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_URI.h>
+
+#include "_test_parc_URI.h"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parcURIAuthority)
+{
+ LONGBOW_RUN_TEST_FIXTURE(parcURIAuthority);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parcURIAuthority)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(parcURIAuthority)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Tests leak memory by %d allocations\n", outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(parcURIAuthority)
+{
+ LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_Parse);
+
+ LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_Acquire);
+
+ LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_Equals);
+
+ LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_GetUserInfo);
+ LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_GetHostName);
+ LONGBOW_RUN_TEST_CASE(parcURIAuthority, parcURIAuthority_GetPort);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(parcURIAuthority)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(parcURIAuthority)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_Parse)
+{
+ char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+
+ PARCURI *uri = parcURI_Parse(uriString);
+
+ PARCURIAuthority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+
+ assertEqualStrings(parcURIAuthority_GetUserInfo(authority), URI_AUTHORITY_USERINFO);
+
+ parcURIAuthority_Release(&authority);
+
+ parcMemory_Deallocate((void **) &uriString);
+ parcURI_Release(&uri);
+
+ // URI without the port
+ uriString = URI_SCHEME "://" URI_AUTHORITY_USERINFO "@" URI_AUTHORITY_HOSTNAME "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+ uri = parcURI_Parse(uriString);
+ authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+
+ assertEqualStrings(parcURIAuthority_GetUserInfo(authority), URI_AUTHORITY_USERINFO);
+
+ parcURIAuthority_Release(&authority);
+ parcURI_Release(&uri);
+
+ // URI with literal V4 address
+ uriString = URI_SCHEME "://" URI_AUTHORITY_LITERAL_HOST "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+ uri = parcURI_Parse(uriString);
+ authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+
+ assertEqualStrings(parcURIAuthority_GetHostName(authority), URI_AUTHORITY_LITERAL_HOSTNAME);
+
+ parcURIAuthority_Release(&authority);
+ parcURI_Release(&uri);
+
+ // URI with literal V6 address
+ uriString = URI_SCHEME "://" URI_AUTHORITY_LITERAL_HOST6 "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+ uri = parcURI_Parse(uriString);
+ authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+
+ assertEqualStrings(parcURIAuthority_GetHostName(authority), URI_AUTHORITY_LITERAL_HOSTNAME6);
+
+ parcURIAuthority_Release(&authority);
+ parcURI_Release(&uri);
+
+ // URI with full literal V6 address
+ uriString = URI_SCHEME "://" URI_AUTHORITY_LITERAL_HOST6_2 "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+ uri = parcURI_Parse(uriString);
+ authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+
+ assertEqualStrings(parcURIAuthority_GetHostName(authority), URI_AUTHORITY_LITERAL_HOSTNAME6_2);
+
+ parcURIAuthority_Release(&authority);
+ parcURI_Release(&uri);
+
+ parcMemory_Deallocate((void **) &uriString);
+}
+
+LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_Acquire)
+{
+ char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+
+ PARCURI *uri = parcURI_Parse(uriString);
+
+ PARCURIAuthority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+ PARCURIAuthority *handle = parcURIAuthority_Acquire(authority);
+
+ assertTrue(parcURIAuthority_Equals(authority, handle), "URI Authorities should be equal since they refer to the same object.");
+
+ parcURIAuthority_Release(&authority);
+ parcURIAuthority_Release(&handle);
+
+ parcMemory_Deallocate((void **) &uriString);
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_Equals)
+{
+ char *uriString1 = URI_SCHEME "://" URI_AUTHORITY;
+ uriString1 = parcMemory_StringDuplicate(uriString1, strlen(uriString1));
+ PARCURI *uri1 = parcURI_Parse(uriString1);
+ PARCURIAuthority *x = parcURIAuthority_Parse(parcURI_GetAuthority(uri1));
+
+ char *uriString2 = URI_SCHEME "://" URI_AUTHORITY;
+ uriString2 = parcMemory_StringDuplicate(uriString2, strlen(uriString2));
+ PARCURI *uri2 = parcURI_Parse(uriString2);
+ PARCURIAuthority *y = parcURIAuthority_Parse(parcURI_GetAuthority(uri2));
+
+ char *uriString3 = URI_SCHEME "://" URI_AUTHORITY;
+ uriString3 = parcMemory_StringDuplicate(uriString3, strlen(uriString3));
+ PARCURI *uri3 = parcURI_Parse(uriString3);
+ PARCURIAuthority *z = parcURIAuthority_Parse(parcURI_GetAuthority(uri3));
+
+ char *differentUriString = URI_SCHEME "://" URI_AUTHORITY_USERINFO;
+ differentUriString = parcMemory_StringDuplicate(differentUriString, strlen(differentUriString));
+ PARCURI *unequalUri = parcURI_Parse(differentUriString);
+ PARCURIAuthority *u = parcURIAuthority_Parse(parcURI_GetAuthority(unequalUri));
+
+ char *uriString5 = URI_SCHEME "://" URI_AUTHORITY_DIFFERENT_PORT;
+ uriString5 = parcMemory_StringDuplicate(uriString5, strlen(uriString5));
+ PARCURI *unequalUri5 = parcURI_Parse(uriString5);
+ PARCURIAuthority *u5 = parcURIAuthority_Parse(parcURI_GetAuthority(unequalUri5));
+
+ char *uriString4 = URI_SCHEME "://" URI_AUTHORITY_DIFFERENT_USER;
+ uriString4 = parcMemory_StringDuplicate(uriString4, strlen(uriString4));
+ PARCURI *unequalUri4 = parcURI_Parse(uriString4);
+ PARCURIAuthority *u4 = parcURIAuthority_Parse(parcURI_GetAuthority(unequalUri4));
+
+ parcObjectTesting_AssertEqualsFunction(parcURIAuthority_Equals, x, y, z, u);
+
+ assertFalse(parcURIAuthority_Equals(x, u4), "Expected URI authorities with different user info to be unequal");
+ assertFalse(parcURIAuthority_Equals(x, u5), "Expected URI authorities with different hsot names to be unequal");
+
+ parcURIAuthority_Release(&x);
+ parcURIAuthority_Release(&y);
+ parcURIAuthority_Release(&z);
+ parcURIAuthority_Release(&u);
+ parcURIAuthority_Release(&u4);
+ parcURIAuthority_Release(&u5);
+
+ parcMemory_Deallocate((void **) &uriString1);
+ parcMemory_Deallocate((void **) &uriString2);
+ parcMemory_Deallocate((void **) &uriString3);
+ parcMemory_Deallocate((void **) &uriString4);
+ parcMemory_Deallocate((void **) &uriString5);
+ parcMemory_Deallocate((void **) &differentUriString);
+
+ parcURI_Release(&uri1);
+ parcURI_Release(&uri2);
+ parcURI_Release(&uri3);
+ parcURI_Release(&unequalUri);
+ parcURI_Release(&unequalUri4);
+ parcURI_Release(&unequalUri5);
+}
+
+LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_GetUserInfo)
+{
+ char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+ PARCURI *uri = parcURI_Parse(uriString);
+ PARCURIAuthority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+
+ assertTrue(strcmp(URI_AUTHORITY_USERINFO, parcURIAuthority_GetUserInfo(authority)) == 0, "URI Authority user info should be equal: %s - %s", URI_AUTHORITY_USERINFO, parcURIAuthority_GetUserInfo(authority));
+
+ parcURIAuthority_Release(&authority);
+
+ parcMemory_Deallocate((void **) &uriString);
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_GetHostName)
+{
+ char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+ PARCURI *uri = parcURI_Parse(uriString);
+ PARCURIAuthority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+
+ assertTrue(strcmp(URI_AUTHORITY_HOSTNAME, parcURIAuthority_GetHostName(authority)) == 0, "URI Authority host name should be equal: %s - %s", URI_AUTHORITY_HOSTNAME, parcURIAuthority_GetHostName(authority));
+
+ parcURIAuthority_Release(&authority);
+
+ parcMemory_Deallocate((void **) &uriString);
+ parcURI_Release(&uri);
+}
+
+LONGBOW_TEST_CASE(parcURIAuthority, parcURIAuthority_GetPort)
+{
+ char *uriString = URI_SCHEME "://" URI_AUTHORITY "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?" URI_QUERY "#" URI_FRAGMENT;
+ uriString = parcMemory_StringDuplicate(uriString, strlen(uriString));
+ PARCURI *uri = parcURI_Parse(uriString);
+ PARCURIAuthority *authority = parcURIAuthority_Parse(parcURI_GetAuthority(uri));
+
+ assertTrue(atol(URI_AUTHORITY_PORT_1) == parcURIAuthority_GetPort(authority),
+ "URI Authority host name should be equal: %ld - %ld", atol(URI_AUTHORITY_PORT_1), parcURIAuthority_GetPort(authority));
+
+ parcURIAuthority_Release(&authority);
+
+ parcMemory_Deallocate((void **) &uriString);
+ parcURI_Release(&uri);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcURIAuthority);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(status);
+}
diff --git a/libparc/parc/algol/test/test_parc_URIPath.c b/libparc/parc/algol/test/test_parc_URIPath.c
new file mode 100644
index 00000000..29f34a96
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_URIPath.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 "../parc_URIPath.c"
+#include <stdint.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_URI.h>
+
+#include "_test_parc_URI.h"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parcURIPath)
+{
+ LONGBOW_RUN_TEST_FIXTURE(parcURIPath);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parcURIPath)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(parcURIPath)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Tests leak memory by %d allocations\n", outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(parcURIPath)
+{
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Acquire);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Parse);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Parse_WithQuery);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Release);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Count);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Append);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_ToString);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Length);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Trim);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Copy);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Equals);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Compare_Identity);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Compare_Equal);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Compare_Unequal);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_Compose);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_StartsWith);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_StartsWith_Equal);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_StartsWith_Fail);
+ LONGBOW_RUN_TEST_CASE(parcURIPath, parcURIPath_BuildString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(parcURIPath)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(parcURIPath)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Acquire)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "//////" URI_PATH_SEGMENT, &pointer);
+ PARCURIPath *handle = parcURIPath_Acquire(path);
+
+ assertTrue(parcURIPath_Equals(path, handle), "URI paths should be equal: %s - %s", parcURIPath_ToString(path), parcURIPath_ToString(handle));
+
+ parcURIPath_Release(&path);
+ parcURIPath_Release(&handle);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Parse)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "//////" URI_PATH_SEGMENT, &pointer);
+ assertNotNull(path, "Expected non-null result.");
+ assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte.");
+
+ char *actualPath = parcURIPath_ToString(path);
+
+ char *expectedPath = URI_PATH_SEGMENT "/" URI_PATH_SEGMENT;
+ assertTrue(strcmp(expectedPath, actualPath) == 0, "Expected %s actual %s", expectedPath, actualPath);
+
+ parcMemory_Deallocate((void **) &actualPath);
+ parcURIPath_Release(&path);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Release)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer);
+ assertNotNull(path, "Expected non-null result.");
+ parcURIPath_Release(&path);
+ assertNull(path, "Expected destroy to null the pointer.");
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Parse_WithQuery)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ assertNotNull(path, "Expected non-null result.");
+ assertTrue(*pointer == '?', "Expected pointer to point to the terminating character.");
+
+ char *actualPath = parcURIPath_ToString(path);
+ char *expectedPath = URI_PATH_SEGMENT "/" URI_PATH_SEGMENT;
+ assertTrue(strcmp(expectedPath, actualPath) == 0, "Expected %s actual %s", expectedPath, actualPath);
+ parcMemory_Deallocate((void **) &actualPath);
+ parcURIPath_Release(&path);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Equals)
+{
+ const char *pointer;
+ PARCURIPath *x = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *y = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *z = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *u1 = parcURIPath_Parse("/" URI_PATH_SEGMENT "a/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *u2 = parcURIPath_Parse("/" URI_PATH_SEGMENT "?query", &pointer);
+
+ parcObjectTesting_AssertEqualsFunction(parcURIPath_Equals, x, y, z, u1, u2);
+
+ parcURIPath_Release(&x);
+ parcURIPath_Release(&y);
+ parcURIPath_Release(&z);
+ parcURIPath_Release(&u1);
+ parcURIPath_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Copy)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *copy = parcURIPath_Copy(path);
+
+ assertTrue(copy != path, "Expected distinct instances of the path.");
+
+ int comparison = parcURIPath_Compare(path, copy);
+
+ assertTrue(comparison == 0, "Expected the copy to compare equal to the original.");
+
+ parcURIPath_Release(&path);
+ parcURIPath_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_StartsWith)
+{
+ const char *pointer;
+ PARCURIPath *base = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *prefix = parcURIPath_Parse("/" URI_PATH_SEGMENT "?query", &pointer);
+
+ bool actual = parcURIPath_StartsWith(base, prefix);
+
+ assertTrue(actual, "Expected true, actual false.");
+
+ parcURIPath_Release(&prefix);
+ parcURIPath_Release(&base);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_StartsWith_Equal)
+{
+ const char *pointer;
+ PARCURIPath *base = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *prefix = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+
+ bool actual = parcURIPath_StartsWith(base, prefix);
+
+ assertTrue(actual, "Expected true, actual false.");
+
+ parcURIPath_Release(&prefix);
+ parcURIPath_Release(&base);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_StartsWith_Fail)
+{
+ const char *pointer;
+ PARCURIPath *base = parcURIPath_Parse("/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *prefix1 = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *prefix2 = parcURIPath_Parse("/" URI_PATH_SEGMENT "A?query", &pointer);
+
+ assertFalse(parcURIPath_StartsWith(base, prefix1),
+ "Expected false, actual true");
+
+ assertFalse(parcURIPath_StartsWith(base, prefix2),
+ "Expected false, actual true");
+
+ parcURIPath_Release(&prefix1);
+ parcURIPath_Release(&prefix2);
+ parcURIPath_Release(&base);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Compose)
+{
+ const char *pointer;
+ PARCURIPath *base = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *expected = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+
+ PARCURISegment *a = parcURISegment_Parse(URI_PATH_SEGMENT, &pointer);
+ PARCURIPath *actual = parcURIPath_Compose(base, a, a, NULL);
+ parcURISegment_Release(&a);
+
+ char *actualString = parcURIPath_ToString(actual);
+ char *expectedString = parcURIPath_ToString(expected);
+ assertTrue(parcURIPath_Compare(expected, actual) == 0, "Expected '%s' actual '%s'\n", expectedString, actualString);
+
+ parcMemory_Deallocate((void **) &actualString);
+ parcMemory_Deallocate((void **) &expectedString);
+
+ parcURIPath_Release(&actual);
+
+ parcURIPath_Release(&expected);
+ parcURIPath_Release(&base);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Compare_Identity)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+
+ PARCURIPath *equivalents[] = {
+ path,
+ parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query",&pointer),
+ NULL,
+ };
+ PARCURIPath *lessers[] = {
+ parcURIPath_Parse("/" URI_PATH_SEGMENT "?query", &pointer),
+ NULL,
+ };
+ PARCURIPath *greaters[] = {
+ parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer),
+ parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "AAA?query", &pointer),
+ NULL,
+ };
+
+ parcObjectTesting_AssertCompareTo(parcURIPath_Compare, path, equivalents, lessers, greaters);
+
+ for (int i = 0; equivalents[i] != NULL; i++) {
+ parcURIPath_Release(&equivalents[i]);
+ }
+ for (int i = 0; lessers[i] != NULL; i++) {
+ parcURIPath_Release(&lessers[i]);
+ }
+ for (int i = 0; greaters[i] != NULL; i++) {
+ parcURIPath_Release(&greaters[i]);
+ }
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Compare_Equal)
+{
+ const char *pointer;
+ PARCURIPath *pathA = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *pathB = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+
+ int comparison = parcURIPath_Compare(pathA, pathB);
+
+ assertTrue(comparison == 0, "Expected 0: equal paths to compare equal. Actual %d", comparison);
+ parcURIPath_Release(&pathA);
+ parcURIPath_Release(&pathB);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Compare_Unequal)
+{
+ const char *pointer;
+ PARCURIPath *pathA = parcURIPath_Parse("/" URI_PATH_SEGMENT "?query", &pointer);
+ PARCURIPath *pathB = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "?query", &pointer);
+
+ int comparison = parcURIPath_Compare(pathA, pathB);
+
+ assertTrue(comparison < 0, "Expected < 0: path A is less than path B. Actual %d", comparison);
+ parcURIPath_Release(&pathA);
+ parcURIPath_Release(&pathB);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Count)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer);
+ assertNotNull(path, "Expected non-null result.");
+ assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte.");
+
+ size_t actual = parcURIPath_Count(path);
+ assertTrue(3 == actual, "Expected %d actual %zd", 3, actual);
+
+ parcURIPath_Release(&path);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_ToString)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer);
+ assertNotNull(path, "Expected non-null result.");
+ assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte.");
+
+ char *actualString = parcURIPath_ToString(path);
+
+ char *expectedString = URI_PATH_SEGMENT "/" URI_PATH_SEGMENT;
+ assertTrue(strcmp(expectedString, actualString) == 0, "Expected %s actual %s", expectedString, actualString);
+
+ parcMemory_Deallocate((void **) &actualString);
+ parcURIPath_Release(&path);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Length)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer);
+ assertNotNull(path, "Expected non-null result.");
+ assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte.");
+
+ size_t actualCount = parcURIPath_Length(path);
+
+ size_t expectedCount = 79;
+ assertTrue(expectedCount == actualCount, "Expected %zd actual %zd", expectedCount, actualCount);
+
+ parcURIPath_Release(&path);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Append)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer);
+
+ PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT, &pointer);
+
+ PARCURIPath *result = parcURIPath_Append(path, segment);
+ assertTrue(result == path, "Expected %p, actual %p", (void *) path, (void *) result);
+
+ size_t actualCount = parcURIPath_Count(path);
+ assertTrue(3 == actualCount, "Expected 3, actual %zd", actualCount);
+
+ char *actualPath = parcURIPath_ToString(path);
+ char *expectedPath = URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT;
+ assertTrue(strcmp(expectedPath, actualPath) == 0, "Expected %s actual %s", expectedPath, actualPath);
+
+ parcMemory_Deallocate((void **) &actualPath);
+ parcURIPath_Release(&path);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_Trim)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT "/" URI_PATH_SEGMENT, &pointer);
+
+ parcURIPath_Trim(path, 2);
+ size_t actualCount = parcURIPath_Count(path);
+ assertTrue(2 == actualCount, "Expected 2, actual %zd", actualCount);
+
+ parcURIPath_Release(&path);
+}
+
+LONGBOW_TEST_CASE(parcURIPath, parcURIPath_BuildString)
+{
+ const char *pointer;
+ PARCURIPath *path = parcURIPath_Parse("/" URI_PATH_SEGMENT, &pointer);
+ PARCBufferComposer *target = parcBufferComposer_Create();
+
+ PARCBufferComposer *string = parcBufferComposer_Create();
+ parcBufferComposer_PutString(string, URI_PATH_SEGMENT);
+
+ PARCBuffer *b1 = parcBufferComposer_ProduceBuffer(string);
+ char *string1 = parcBuffer_ToString(b1);
+ parcBuffer_Release(&b1);
+
+ parcURIPath_BuildString(path, target);
+ PARCBuffer *b2 = parcBufferComposer_ProduceBuffer(target);
+ char *string2 = parcBuffer_ToString(b2);
+ parcBuffer_Release(&b2);
+
+ assertTrue(strncmp(string1, string2, strlen(string1)) == 0, "String representations of the paths should be equal: %s - %s", string1, string2);
+
+ parcMemory_Deallocate((void **) &string1);
+ parcMemory_Deallocate((void **) &string2);
+
+ parcBufferComposer_Release(&string);
+ parcBufferComposer_Release(&target);
+ parcURIPath_Release(&path);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcURIPath);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(status);
+}
diff --git a/libparc/parc/algol/test/test_parc_URISegment.c b/libparc/parc/algol/test/test_parc_URISegment.c
new file mode 100644
index 00000000..640bab89
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_URISegment.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "../parc_URISegment.c"
+#include <LongBow/unit-test.h>
+
+#include <stdint.h>
+
+#include <parc/algol/parc_URI.h>
+
+#include "_test_parc_URI.h"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parcURISegment)
+{
+ LONGBOW_RUN_TEST_FIXTURE(parcURISegment);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parcURISegment)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(parcURISegment)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Tests leak memory by %d allocations\n", outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(parcURISegment)
+{
+ LONGBOW_RUN_TEST_CASE(parcURISegment, _parcURISegment_fromHexDigit);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, _parcURISegment_parsePercentEncoded);
+
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Acquire);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Create);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Parse);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Parse_WithExtraSlashes);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Parse_WithInvalidPercentage);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Release);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Length);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_ToString);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Equals_Contract);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Compare_Contract);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_Clone);
+ LONGBOW_RUN_TEST_CASE(parcURISegment, parcURISegment_GetBuffer);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(parcURISegment)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(parcURISegment)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(parcURISegment, _parcURISegment_fromHexDigit)
+{
+ const char test = 'G';
+ signed char actual = _fromHexDigit(test);
+ assertTrue(-1 == (int) actual, "Invalid hex digit should not be changed to a decimal value, we expect -1 as the result");
+}
+
+LONGBOW_TEST_CASE(parcURISegment, _parcURISegment_parsePercentEncoded)
+{
+ unsigned char buffer;
+
+ const char *test1 = "0G";
+ const char *result1 = _parsePercentEncoded(test1, &buffer);
+ assertTrue(NULL == result1, "Expected NULL parsed byte from invalid encoded percentage string, got %s", result1);
+ const char *test2 = "GG";
+ const char *result2 = _parsePercentEncoded(test2, &buffer);
+ assertTrue(NULL == result2, "Expected NULL parsed byte from invalid encoded percentage string, got %s", result2);
+ const char *test3 = "";
+ const char *result3 = _parsePercentEncoded(test3, &buffer);
+ assertTrue(NULL == result3, "Expected NULL parsed byte from empty encoded percentage string, got %s", result3);
+ const char *test4 = "0";
+ const char *result4 = _parsePercentEncoded(test4, &buffer);
+ assertTrue(NULL == result4, "Expected NULL parsed byte from half-empty encoded percentage string, got %s", result4);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Acquire)
+{
+ char *expected = URI_PATH_SEGMENT;
+
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(expected, &pointer);
+ PARCURISegment *handle = parcURISegment_Acquire(segment);
+ assertTrue(parcURISegment_Equals(segment, handle), "Expected URI segments to be equal: %s - %s", parcURISegment_ToString(segment), parcURISegment_ToString(handle));
+
+ parcURISegment_Release(&segment);
+ parcURISegment_Release(&handle);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Create)
+{
+ char *expected = URI_PATH_SEGMENT;
+
+ PARCURISegment *segment = parcURISegment_Create(strlen(expected), (unsigned char *) expected);
+ assertNotNull(segment, "Expected non-null result.");
+
+ parcURISegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Parse)
+{
+ char *expected = URI_PATH_SEGMENT;
+
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(expected, &pointer);
+ assertNotNull(segment, "Expected non-null result.");
+
+ char *expectedBytes = URI_PATH_SEGMENT;
+
+ char *actualBytes = parcURISegment_ToString(segment);
+
+ assertTrue(strcmp(expectedBytes, actualBytes) == 0,
+ "Expected %s actual %s", expectedBytes, actualBytes);
+ parcMemory_Deallocate((void **) &actualBytes);
+
+ assertTrue(parcURISegment_Length(segment) == 39,
+ "Expected 39, actual %zd", parcURISegment_Length(segment));
+ assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte.");
+
+ parcURISegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Parse_WithExtraSlashes)
+{
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT_WITH_SLASHES, &pointer);
+ assertNotNull(segment, "Expected non-null result.");
+
+ char *expectedBytes = URI_PATH_SEGMENT;
+
+ char *actualBytes = parcURISegment_ToString(segment);
+
+ assertTrue(strcmp(expectedBytes, actualBytes) == 0,
+ "Expected %s actual %s", expectedBytes, actualBytes);
+ parcMemory_Deallocate((void **) &actualBytes);
+
+ assertTrue(parcURISegment_Length(segment) == 39,
+ "Expected 39, actual %zd", parcURISegment_Length(segment));
+ assertTrue(*pointer == '/', "Expected pointer to point to the slash character: %c", *pointer);
+
+ parcURISegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Parse_WithInvalidPercentage)
+{
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT "%G", &pointer);
+
+ assertNull(segment, "Parsed segment should be NULL since the last percent-encoded byte is invalid");
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Release)
+{
+ char *expected = URI_PATH_SEGMENT;
+
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(expected, &pointer);
+ assertNotNull(segment, "Expected non-null result.");
+
+ parcURISegment_Release(&segment);
+ assertNull(segment, "Expected destroy to null the pointer");
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Equals_Contract)
+{
+ char *expected = URI_PATH_SEGMENT;
+
+ const char *pointer;
+ PARCURISegment *x = parcURISegment_Parse(expected, &pointer);
+ PARCURISegment *y = parcURISegment_Parse(expected, &pointer);
+ PARCURISegment *z = parcURISegment_Parse(expected, &pointer);
+
+ parcObjectTesting_AssertEqualsFunction(parcURISegment_Equals, x, y, z, NULL);
+
+ parcURISegment_Release(&x);
+ parcURISegment_Release(&y);
+ parcURISegment_Release(&z);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Clone)
+{
+ char *expected = URI_PATH_SEGMENT;
+
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(expected, &pointer);
+ PARCURISegment *copy = parcURISegment_Clone(segment);
+
+ assertTrue(segment != copy, "Expected different instances of equal segments.");
+
+ int comparison = parcURISegment_Compare(segment, copy);
+ assertTrue(comparison == 0, "Expected equal segments.");
+
+ assertTrue(parcURISegment_Equals(segment, copy), "Expected equal segments");
+
+ parcURISegment_Release(&copy);
+ parcURISegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Length)
+{
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT, &pointer);
+ assertNotNull(segment,
+ "Expected non-null result.");
+ assertTrue(*pointer == 0,
+ "Expected pointer to point to the null terminating byte.");
+
+ size_t actual = parcURISegment_Length(segment);
+
+ assertTrue(actual == 39,
+ "Expected 39, actual %zd", actual);
+
+ parcURISegment_Release(&segment);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_Compare_Contract)
+{
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse("MMM", &pointer);
+
+ PARCURISegment *equivalents[] = {
+ segment,
+ parcURISegment_Parse("MMM",&pointer),
+ NULL,
+ };
+ PARCURISegment *lessers[] = {
+ parcURISegment_Parse("MM", &pointer),
+ parcURISegment_Parse("MML", &pointer),
+ NULL,
+ };
+ PARCURISegment *greaters[] = {
+ parcURISegment_Parse("MMMM", &pointer),
+ parcURISegment_Parse("MMN", &pointer),
+ NULL,
+ };
+ parcObjectTesting_AssertCompareTo(parcURISegment_Compare, segment, equivalents, lessers, greaters);
+
+ for (int i = 0; equivalents[i] != NULL; i++) {
+ parcURISegment_Release(&equivalents[i]);
+ }
+ for (int i = 0; lessers[i] != NULL; i++) {
+ parcURISegment_Release(&lessers[i]);
+ }
+ for (int i = 0; greaters[i] != NULL; i++) {
+ parcURISegment_Release(&greaters[i]);
+ }
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_ToString)
+{
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT, &pointer);
+ assertNotNull(segment, "Expected non-null result.");
+ assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte.");
+
+ char *actual = parcURISegment_ToString(segment);
+
+ assertTrue(strcmp(URI_PATH_SEGMENT, actual) == 0, "Expected %s, actual %s", URI_PATH_SEGMENT, actual);
+
+ parcURISegment_Release(&segment);
+
+ parcMemory_Deallocate((void **) &actual);
+}
+
+LONGBOW_TEST_CASE(parcURISegment, parcURISegment_GetBuffer)
+{
+ const char *pointer;
+ PARCURISegment *segment = parcURISegment_Parse(URI_PATH_SEGMENT, &pointer);
+ assertNotNull(segment, "Expected non-null result.");
+ assertTrue(*pointer == 0, "Expected pointer to point to the null terminating byte.");
+
+ PARCBuffer *buffer = parcURISegment_GetBuffer(segment);
+
+ char *expected = URI_PATH_SEGMENT;
+ char *actual = (char *) parcBuffer_Overlay(buffer, 0);
+ size_t compareLength = strlen(URI_PATH_SEGMENT);
+ assertTrue(strncmp(expected, actual, compareLength), "Buffer does not contain original data.");
+
+ parcURISegment_Release(&segment);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parcURISegment);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(status);
+}
diff --git a/libparc/parc/algol/test/test_parc_Varint.c b/libparc/parc/algol/test/test_parc_Varint.c
new file mode 100755
index 00000000..cf0c865c
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Varint.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../parc_Varint.c"
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+LONGBOW_TEST_RUNNER(parc_VarInt)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parc_VarInt)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_VarInt)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_And);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AndUint16);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AndUint32);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AndUint64);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AndUint8);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AsSize);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AsUint16);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AsUint32);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AsUint64);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_AsUint8);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_EqualsUint16);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_EqualsUint32);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_EqualsUint64);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_EqualsUint8);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_FromByteBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_FromUTF8ByteBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_FromUint32);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_FromUint64);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_FromUint8);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_New);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_Or);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_OrUint16);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_OrUint32);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_OrUint64);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_OrUint8);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_Set);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_ShiftLeft);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_ShiftRight);
+ LONGBOW_RUN_TEST_CASE(Global, parcVarint_ToString);
+}
+
+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, parcVarint_And)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AndUint16)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AndUint32)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AndUint64)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AndUint8)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AsSize)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AsUint16)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AsUint32)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AsUint64)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_AsUint8)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_Destroy)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_Equals)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_EqualsUint16)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_EqualsUint32)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_EqualsUint64)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_EqualsUint8)
+{
+ unsigned char expected = 5;
+ PARCVarint *a = parcVarint_FromUint8(expected);
+ PARCVarint *b = parcVarint_FromUint8(expected);
+
+ assertTrue(parcVarint_Equals(a, b), "Equal instances failed to be equal.");
+ parcVarint_Destroy(&a);
+ parcVarint_Destroy(&b);
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_FromByteBuffer)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_FromUTF8ByteBuffer)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "10");
+ PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+
+ PARCVarint *varint = parcVarint_FromUTF8ByteBuffer(buffer);
+
+ uint32_t actual = parcVarint_AsUint32(varint);
+
+ assertTrue(10 == actual, "Expected 10 actual %u", actual);
+ parcBuffer_Release(&buffer);
+ parcBufferComposer_Release(&composer);
+ parcVarint_Destroy(&varint);
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_FromUint32)
+{
+ uint32_t value = 0x12345678;
+ PARCVarint *a = parcVarint_FromUint32(value);
+ assertNotNull(a, "Probably out of memory.");
+
+ uint32_t actual = parcVarint_AsUint32(a);
+
+ assertEqual(value, actual, "%u");
+
+ parcVarint_Destroy(&a);
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_FromUint64)
+{
+ uint64_t value = 0x1234567812345678;
+ PARCVarint *a = parcVarint_FromUint64(value);
+ assertNotNull(a, "Probably out of memory.");
+
+ uint64_t actual = parcVarint_AsUint64(a);
+
+ assertEqual(value, actual, "%" PRIu64);
+
+ parcVarint_Destroy(&a);
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_FromUint8)
+{
+ uint8_t value = 0x12;
+ PARCVarint *a = parcVarint_FromUint8(value);
+ assertNotNull(a, "Probably out of memory.");
+
+ uint8_t actual = parcVarint_AsUint8(a);
+
+ assertEqual(value, actual, "%d");
+
+ parcVarint_Destroy(&a);
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_New)
+{
+ PARCVarint *a = parcVarint_Create();
+ assertNotNull(a, "Probably out of memory.");
+
+ parcVarint_Destroy(&a);
+ assertNull(a, "Destroy failed to nullify.");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_Or)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_OrUint16)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_OrUint32)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_OrUint64)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_OrUint8)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_Set)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_ShiftLeft)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_ShiftRight)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcVarint_ToString)
+{
+ 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[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_VarInt);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/algol/test/test_parc_Vector.c b/libparc/parc/algol/test/test_parc_Vector.c
new file mode 100644
index 00000000..bea435dc
--- /dev/null
+++ b/libparc/parc/algol/test/test_parc_Vector.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 <config.h>
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+#include "../parc_Vector.c"
+
+LONGBOW_TEST_RUNNER(PARCVector)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(PARCVector)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(PARCVector)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("Tests leak memory by %d allocations\n", outstandingAllocations);
+ exit(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcVectorDestroy);
+ LONGBOW_RUN_TEST_CASE(Global, parcVectorGetLength);
+ LONGBOW_RUN_TEST_CASE(Global, parcVectorGetPointer);
+ LONGBOW_RUN_TEST_CASE(Global, parcVectorCreate);
+}
+
+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, parcVectorDestroy)
+{
+ const char *string = "Hello World";
+
+ PARCVector *x = parcVector_Create((void *) string, strlen(string));
+ parcVector_Destroy(&x);
+ assertNull(x, "Destroy did not nullify.");
+}
+
+LONGBOW_TEST_CASE(Global, parcVectorGetLength)
+{
+ const char *string = "Hello World";
+
+ PARCVector *x = parcVector_Create((void *) string, strlen(string));
+ size_t expected = strlen(string);
+ size_t actual = parcVector_GetLength(x);
+ assertEqual(expected, actual, "%zd");
+ parcVector_Destroy(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcVectorGetPointer)
+{
+ const char *expected = "Hello World";
+
+ PARCVector *x = parcVector_Create((void *) expected, strlen(expected));
+ const char *actual = parcVector_GetPointer(x);
+
+ assertEqual((void *) expected, (void *) actual, "%p");
+
+ parcVector_Destroy(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcVectorCreate)
+{
+ const char *string = "Hello World";
+
+ PARCVector *x = parcVector_Create((void *) string, strlen(string));
+ assertNotNull(x, "Probably out of memory.");
+ parcVector_Destroy(&x);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(PARCVector);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(status);
+}
diff --git a/libparc/parc/concurrent/.gitignore b/libparc/parc/concurrent/.gitignore
new file mode 100644
index 00000000..e6ed7cc3
--- /dev/null
+++ b/libparc/parc/concurrent/.gitignore
@@ -0,0 +1,5 @@
+parcConcurrent_About.c
+parcConcurrent_About.h
+
+test/test_parc_RingBuffer_1x1
+test/test_parc_RingBuffer_NxM
diff --git a/libparc/parc/concurrent/parc_AtomicUint16.c b/libparc/parc/concurrent/parc_AtomicUint16.c
new file mode 100755
index 00000000..24c9f922
--- /dev/null
+++ b/libparc/parc/concurrent/parc_AtomicUint16.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/concurrent/parc_AtomicUint16.h>
+
+struct PARCAtomicUint16 {
+ uint16_t value;
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_t mutex;
+#endif
+};
+
+static void
+_parcAtomicUint16_Finalize(PARCAtomicUint16 **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCAtomicUint16 pointer.");
+
+ parcAtomicUint16_OptionalAssertValid((*instancePtr));
+
+ /* cleanup the instance fields here */
+}
+
+parcObject_ImplementAcquire(parcAtomicUint16, PARCAtomicUint16);
+
+parcObject_ImplementRelease(parcAtomicUint16, PARCAtomicUint16);
+
+parcObject_ExtendPARCObject(PARCAtomicUint16, _parcAtomicUint16_Finalize, parcAtomicUint16_Copy, NULL, parcAtomicUint16_Equals, parcAtomicUint16_Compare, parcAtomicUint16_HashCode, NULL);
+
+
+void
+parcAtomicUint16_AssertValid(const PARCAtomicUint16 *instance)
+{
+ assertTrue(parcAtomicUint16_IsValid(instance),
+ "PARCAtomicUint16 is not valid.");
+}
+
+PARCAtomicUint16 *
+parcAtomicUint16_Create(uint16_t value)
+{
+ PARCAtomicUint16 *result = parcObject_CreateAndClearInstance(PARCAtomicUint16);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_init(&result->mutex, NULL);
+ result->value = value;
+#else
+ *result = value;
+#endif
+
+ return result;
+}
+
+int
+parcAtomicUint16_Compare(const PARCAtomicUint16 *instance, const PARCAtomicUint16 *other)
+{
+ int16_t comparison = parcAtomicUint16_GetValue(instance) - parcAtomicUint16_GetValue(other);
+
+ int result = 0;
+ if (comparison < 0) {
+ result = -1;
+ } else if (comparison > 0) {
+ result = 1;
+ }
+
+ return result;
+}
+
+PARCAtomicUint16 *
+parcAtomicUint16_Copy(const PARCAtomicUint16 *original)
+{
+ PARCAtomicUint16 *result = parcAtomicUint16_Create(parcAtomicUint16_GetValue(original));
+
+ return result;
+}
+
+bool
+parcAtomicUint16_Equals(const PARCAtomicUint16 *x, const PARCAtomicUint16 *y)
+{
+ bool result = false;
+
+ result = parcAtomicUint16_GetValue(x) == parcAtomicUint16_GetValue(y);
+
+ return result;
+}
+
+PARCHashCode
+parcAtomicUint16_HashCode(const PARCAtomicUint16 *instance)
+{
+ PARCHashCode result = (PARCHashCode) parcAtomicUint16_GetValue(instance);
+
+ return result;
+}
+
+bool
+parcAtomicUint16_IsValid(const PARCAtomicUint16 *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+uint16_t
+parcAtomicUint16_GetValue(const PARCAtomicUint16 *instance)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ return instance->value;
+#else
+ return *instance;
+#endif
+}
+
+uint16_t
+parcAtomicUint16_AddImpl(PARCAtomicUint16 *value, uint16_t addend)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ value->value += addend;
+ uint16_t result = value->value;
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ return __sync_add_and_fetch(value, addend);
+#endif
+}
+
+uint16_t
+parcAtomicUint16_SubtractImpl(PARCAtomicUint16 *value, uint16_t subtrahend)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ value->value -= subtrahend;
+ uint16_t result = value->value;
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ return __sync_sub_and_fetch(value, subtrahend);
+#endif
+}
+
+bool
+parcAtomicUint16_CompareAndSwapImpl(PARCAtomicUint16 *value, uint16_t predicate, uint16_t newValue)
+{
+ bool result = false;
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ if (value->value == predicate) {
+ value->value = newValue;
+ result = true;
+ }
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ result = __sync_bool_compare_and_swap(value, predicate, newValue);
+#endif
+ return result;
+}
diff --git a/libparc/parc/concurrent/parc_AtomicUint16.h b/libparc/parc/concurrent/parc_AtomicUint16.h
new file mode 100755
index 00000000..ff6a4fc3
--- /dev/null
+++ b/libparc/parc/concurrent/parc_AtomicUint16.h
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_AtomicUint16.h
+ * @ingroup threading
+ * @brief An atomically updated 16-bit unsigned integer.
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_AtomicUint16
+#define PARCLibrary_parc_AtomicUint16
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_JSON.h>
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+#include <pthread.h>
+struct PARCAtomicUint16;
+typedef struct PARCAtomicUint16 PARCAtomicUint16;
+#else
+typedef uint16_t PARCAtomicUint16;
+#endif
+
+
+PARCAtomicUint16 *parcAtomicInteger_CreateUint16(uint16_t value);
+
+uint16_t parcAtomicUint16_AddImpl(PARCAtomicUint16 *value, uint16_t addend);
+
+uint16_t parcAtomicUint16_SubtractImpl(PARCAtomicUint16 *value, uint16_t subtrahend);
+
+bool parcAtomicUint16_CompareAndSwapImpl(PARCAtomicUint16 *value, uint16_t predicate, uint16_t newValue);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+
+#define parcAtomicUint16_Add parcAtomicUint16_AddImpl
+
+#define parcAtomicUint16_Subtract parcAtomicUint16_SubtractImpl
+
+#define parcAtomicUint16_CompareAndSwap parcAtomicUint16_CompareAndSwapImpl
+
+#else
+
+#define parcAtomicUint16_Add(_atomic_uint16_, _addend_) \
+ __sync_add_and_fetch(_atomic_uint16_, _addend_)
+
+#define parcAtomicUint16_Subtract(_atomic_uint16_, _subtrahend_) \
+ __sync_sub_and_fetch(_atomic_uint16_, _subtrahend_)
+
+#define parcAtomicUint16_CompareAndSwap(_atomic_uint16_, _predicate_, _newValue_) \
+ __sync_bool_compare_and_swap(_atomic_uint16_, _predicate_, _newValue_)
+#endif
+
+#define parcAtomicUint16_Increment(_atomic_uint16_) parcAtomicUint16_Add(_atomic_uint16_, 1)
+#define parcAtomicUint16_Decrement(_atomic_uint16_) parcAtomicUint16_Subtract(_atomic_uint16_, 1)
+
+/**
+ * Increase the number of references to a `PARCAtomicUint16` instance.
+ *
+ * Note that new `PARCAtomicUint16` is not created,
+ * only that the given `PARCAtomicUint16` reference count is incremented.
+ * Discard the reference by invoking `parcAtomicUint16_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint16 instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ *
+ * PARCAtomicUint16 *b = parcAtomicUint16_Acquire();
+ *
+ * parcAtomicUint16_Release(&a);
+ * parcAtomicUint16_Release(&b);
+ * }
+ * @endcode
+ */
+PARCAtomicUint16 *parcAtomicUint16_Acquire(const PARCAtomicUint16 *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcAtomicUint16_OptionalAssertValid(_instance_)
+#else
+# define parcAtomicUint16_OptionalAssertValid(_instance_) parcAtomicUint16_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCAtomicUint16` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint16 instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ *
+ * parcAtomicUint16_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcAtomicUint16_Release(&b);
+ * }
+ * @endcode
+ */
+void parcAtomicUint16_AssertValid(const PARCAtomicUint16 *instance);
+
+/**
+ * Create an instance of PARCAtomicUint16
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCAtomicUint16 instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ *
+ * parcAtomicUint16_Release(&b);
+ * }
+ * @endcode
+ */
+PARCAtomicUint16 *parcAtomicUint16_Create(uint16_t);
+
+/**
+ * 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 PARCAtomicUint16 instance.
+ * @param [in] other A pointer to a valid PARCAtomicUint16 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
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ * PARCAtomicUint16 *b = parcAtomicUint16_Create();
+ *
+ * if (parcAtomicUint16_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcAtomicUint16_Release(&a);
+ * parcAtomicUint16_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcAtomicUint16_Equals
+ */
+int parcAtomicUint16_Compare(const PARCAtomicUint16 *instance, const PARCAtomicUint16 *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 PARCAtomicUint16 instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCAtomicUint16` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ *
+ * PARCAtomicUint16 *copy = parcAtomicUint16_Copy(&b);
+ *
+ * parcAtomicUint16_Release(&b);
+ * parcAtomicUint16_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCAtomicUint16 *parcAtomicUint16_Copy(const PARCAtomicUint16 *original);
+
+/**
+ * Determine if two `PARCAtomicUint16` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCAtomicUint16` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcAtomicUint16_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcAtomicUint16_Equals(x, y)` must return true if and only if
+ * `parcAtomicUint16_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcAtomicUint16_Equals(x, y)` returns true and
+ * `parcAtomicUint16_Equals(y, z)` returns true,
+ * then `parcAtomicUint16_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcAtomicUint16_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcAtomicUint16_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCAtomicUint16 instance.
+ * @param [in] y A pointer to a valid PARCAtomicUint16 instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ * PARCAtomicUint16 *b = parcAtomicUint16_Create();
+ *
+ * if (parcAtomicUint16_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcAtomicUint16_Release(&a);
+ * parcAtomicUint16_Release(&b);
+ * }
+ * @endcode
+ * @see parcAtomicUint16_HashCode
+ */
+bool parcAtomicUint16_Equals(const PARCAtomicUint16 *x, const PARCAtomicUint16 *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 parcAtomicUint16_Equals} method,
+ * then calling the {@link parcAtomicUint16_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 parcAtomicUint16_Equals} function,
+ * then calling the `parcAtomicUint16_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint16 instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ *
+ * PARCHashCode hashValue = parcAtomicUint16_HashCode(buffer);
+ * parcAtomicUint16_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcAtomicUint16_HashCode(const PARCAtomicUint16 *instance);
+
+/**
+ * Determine if an instance of `PARCAtomicUint16` 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 PARCAtomicUint16 instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ *
+ * if (parcAtomicUint16_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcAtomicUint16_Release(&b);
+ * }
+ * @endcode
+ */
+bool parcAtomicUint16_IsValid(const PARCAtomicUint16 *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCAtomicUint16` 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
+ * {
+ * PARCAtomicUint16 *a = parcAtomicUint16_Create();
+ *
+ * parcAtomicUint16_Release(&a);
+ * }
+ * @endcode
+ */
+void parcAtomicUint16_Release(PARCAtomicUint16 **instancePtr);
+
+/**
+ * Get the current value of the given `PARCAtomicUint16` instance.
+ *
+ * @param [in] instance A pointer to a valid `PARCAtomicUint16` instance.
+ *
+ * @return the current value of the given `PARCAtomicUint16` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+ *
+ * uint16_t value = parcAtomicUint16_GetValue(instance);
+ *
+ * parcAtomicUint16_Release(&instance);
+ * }
+ * @endcode
+ */
+uint16_t parcAtomicUint16_GetValue(const PARCAtomicUint16 *instance);
+#endif
diff --git a/libparc/parc/concurrent/parc_AtomicUint32.c b/libparc/parc/concurrent/parc_AtomicUint32.c
new file mode 100755
index 00000000..32ed7a6a
--- /dev/null
+++ b/libparc/parc/concurrent/parc_AtomicUint32.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/concurrent/parc_AtomicUint32.h>
+
+struct PARCAtomicUint32 {
+ uint32_t value;
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_t mutex;
+#endif
+};
+
+static void
+_parcAtomicUint32_Finalize(PARCAtomicUint32 **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCAtomicUint32 pointer.");
+
+ parcAtomicUint32_OptionalAssertValid((*instancePtr));
+
+ /* cleanup the instance fields here */
+}
+
+parcObject_ImplementAcquire(parcAtomicUint32, PARCAtomicUint32);
+
+parcObject_ImplementRelease(parcAtomicUint32, PARCAtomicUint32);
+
+parcObject_ExtendPARCObject(PARCAtomicUint32, _parcAtomicUint32_Finalize, parcAtomicUint32_Copy, NULL, parcAtomicUint32_Equals, parcAtomicUint32_Compare, parcAtomicUint32_HashCode, NULL);
+
+
+void
+parcAtomicUint32_AssertValid(const PARCAtomicUint32 *instance)
+{
+ assertTrue(parcAtomicUint32_IsValid(instance),
+ "PARCAtomicUint32 is not valid.");
+}
+
+PARCAtomicUint32 *
+parcAtomicUint32_Create(uint32_t value)
+{
+ PARCAtomicUint32 *result = parcObject_CreateAndClearInstance(PARCAtomicUint32);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_init(&result->mutex, NULL);
+ result->value = value;
+#else
+ *result = value;
+#endif
+
+ return result;
+}
+
+int
+parcAtomicUint32_Compare(const PARCAtomicUint32 *instance, const PARCAtomicUint32 *other)
+{
+ int32_t comparison = parcAtomicUint32_GetValue(instance) - parcAtomicUint32_GetValue(other);
+
+ int result = 0;
+ if (comparison < 0) {
+ result = -1;
+ } else if (comparison > 0) {
+ result = 1;
+ }
+
+ return result;
+}
+
+PARCAtomicUint32 *
+parcAtomicUint32_Copy(const PARCAtomicUint32 *original)
+{
+ PARCAtomicUint32 *result = parcAtomicUint32_Create(parcAtomicUint32_GetValue(original));
+
+ return result;
+}
+
+bool
+parcAtomicUint32_Equals(const PARCAtomicUint32 *x, const PARCAtomicUint32 *y)
+{
+ bool result = false;
+
+ result = parcAtomicUint32_GetValue(x) == parcAtomicUint32_GetValue(y);
+
+ return result;
+}
+
+PARCHashCode
+parcAtomicUint32_HashCode(const PARCAtomicUint32 *instance)
+{
+ PARCHashCode result = (PARCHashCode) parcAtomicUint32_GetValue(instance);
+
+ return result;
+}
+
+bool
+parcAtomicUint32_IsValid(const PARCAtomicUint32 *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+uint32_t
+parcAtomicUint32_GetValue(const PARCAtomicUint32 *instance)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ return instance->value;
+#else
+ return *instance;
+#endif
+}
+
+uint32_t
+parcAtomicUint32_AddImpl(PARCAtomicUint32 *value, uint32_t addend)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ value->value += addend;
+ uint32_t result = value->value;
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ return __sync_add_and_fetch(value, addend);
+#endif
+}
+
+uint32_t
+parcAtomicUint32_SubtractImpl(PARCAtomicUint32 *value, uint32_t subtrahend)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ value->value -= subtrahend;
+ uint32_t result = value->value;
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ return __sync_sub_and_fetch(value, subtrahend);
+#endif
+}
+
+bool
+parcAtomicUint32_CompareAndSwapImpl(PARCAtomicUint32 *value, uint32_t predicate, uint32_t newValue)
+{
+ bool result = false;
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ if (value->value == predicate) {
+ value->value = newValue;
+ result = true;
+ }
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ result = __sync_bool_compare_and_swap(value, predicate, newValue);
+#endif
+ return result;
+}
diff --git a/libparc/parc/concurrent/parc_AtomicUint32.h b/libparc/parc/concurrent/parc_AtomicUint32.h
new file mode 100755
index 00000000..870cbe80
--- /dev/null
+++ b/libparc/parc/concurrent/parc_AtomicUint32.h
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_AtomicUint32.h
+ * @ingroup threading
+ * @brief An atomically updated 32-bit unsigned integer.
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_AtomicUint32
+#define PARCLibrary_parc_AtomicUint32
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_JSON.h>
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+#include <pthread.h>
+struct PARCAtomicUint32;
+typedef struct PARCAtomicUint32 PARCAtomicUint32;
+#else
+typedef uint32_t PARCAtomicUint32;
+#endif
+
+
+PARCAtomicUint32 *parcAtomicInteger_CreateUint32(uint32_t value);
+
+uint32_t parcAtomicUint32_AddImpl(PARCAtomicUint32 *value, uint32_t addend);
+
+uint32_t parcAtomicUint32_SubtractImpl(PARCAtomicUint32 *value, uint32_t subtrahend);
+
+bool parcAtomicUint32_CompareAndSwapImpl(PARCAtomicUint32 *value, uint32_t predicate, uint32_t newValue);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+
+#define parcAtomicUint32_Add parcAtomicUint32_AddImpl
+
+#define parcAtomicUint32_Subtract parcAtomicUint32_SubtractImpl
+
+#define parcAtomicUint32_CompareAndSwap parcAtomicUint32_CompareAndSwapImpl
+
+#else
+
+#define parcAtomicUint32_Add(_atomic_uint32_, _addend_) \
+ __sync_add_and_fetch(_atomic_uint32_, _addend_)
+
+#define parcAtomicUint32_Subtract(_atomic_uint32_, _subtrahend_) \
+ __sync_sub_and_fetch(_atomic_uint32_, _subtrahend_)
+
+#define parcAtomicUint32_CompareAndSwap(_atomic_uint32_, _predicate_, _newValue_) \
+ __sync_bool_compare_and_swap(_atomic_uint32_, _predicate_, _newValue_)
+#endif
+
+#define parcAtomicUint32_Increment(_atomic_uint32_) parcAtomicUint32_Add(_atomic_uint32_, 1)
+#define parcAtomicUint32_Decrement(_atomic_uint32_) parcAtomicUint32_Subtract(_atomic_uint32_, 1)
+
+/**
+ * Increase the number of references to a `PARCAtomicUint32` instance.
+ *
+ * Note that new `PARCAtomicUint32` is not created,
+ * only that the given `PARCAtomicUint32` reference count is incremented.
+ * Discard the reference by invoking `parcAtomicUint32_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint32 instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ *
+ * PARCAtomicUint32 *b = parcAtomicUint32_Acquire();
+ *
+ * parcAtomicUint32_Release(&a);
+ * parcAtomicUint32_Release(&b);
+ * }
+ * @endcode
+ */
+PARCAtomicUint32 *parcAtomicUint32_Acquire(const PARCAtomicUint32 *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcAtomicUint32_OptionalAssertValid(_instance_)
+#else
+# define parcAtomicUint32_OptionalAssertValid(_instance_) parcAtomicUint32_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCAtomicUint32` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint32 instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ *
+ * parcAtomicUint32_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcAtomicUint32_Release(&b);
+ * }
+ * @endcode
+ */
+void parcAtomicUint32_AssertValid(const PARCAtomicUint32 *instance);
+
+/**
+ * Create an instance of PARCAtomicUint32
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCAtomicUint32 instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ *
+ * parcAtomicUint32_Release(&b);
+ * }
+ * @endcode
+ */
+PARCAtomicUint32 *parcAtomicUint32_Create(uint32_t);
+
+/**
+ * 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 PARCAtomicUint32 instance.
+ * @param [in] other A pointer to a valid PARCAtomicUint32 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
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ * PARCAtomicUint32 *b = parcAtomicUint32_Create();
+ *
+ * if (parcAtomicUint32_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcAtomicUint32_Release(&a);
+ * parcAtomicUint32_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcAtomicUint32_Equals
+ */
+int parcAtomicUint32_Compare(const PARCAtomicUint32 *instance, const PARCAtomicUint32 *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 PARCAtomicUint32 instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCAtomicUint32` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ *
+ * PARCAtomicUint32 *copy = parcAtomicUint32_Copy(&b);
+ *
+ * parcAtomicUint32_Release(&b);
+ * parcAtomicUint32_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCAtomicUint32 *parcAtomicUint32_Copy(const PARCAtomicUint32 *original);
+
+/**
+ * Determine if two `PARCAtomicUint32` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCAtomicUint32` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcAtomicUint32_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcAtomicUint32_Equals(x, y)` must return true if and only if
+ * `parcAtomicUint32_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcAtomicUint32_Equals(x, y)` returns true and
+ * `parcAtomicUint32_Equals(y, z)` returns true,
+ * then `parcAtomicUint32_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcAtomicUint32_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcAtomicUint32_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCAtomicUint32 instance.
+ * @param [in] y A pointer to a valid PARCAtomicUint32 instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ * PARCAtomicUint32 *b = parcAtomicUint32_Create();
+ *
+ * if (parcAtomicUint32_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcAtomicUint32_Release(&a);
+ * parcAtomicUint32_Release(&b);
+ * }
+ * @endcode
+ * @see parcAtomicUint32_HashCode
+ */
+bool parcAtomicUint32_Equals(const PARCAtomicUint32 *x, const PARCAtomicUint32 *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 parcAtomicUint32_Equals} method,
+ * then calling the {@link parcAtomicUint32_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 parcAtomicUint32_Equals} function,
+ * then calling the `parcAtomicUint32_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint32 instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ *
+ * PARCHashCode hashValue = parcAtomicUint32_HashCode(buffer);
+ * parcAtomicUint32_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcAtomicUint32_HashCode(const PARCAtomicUint32 *instance);
+
+/**
+ * Determine if an instance of `PARCAtomicUint32` 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 PARCAtomicUint32 instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ *
+ * if (parcAtomicUint32_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcAtomicUint32_Release(&b);
+ * }
+ * @endcode
+ */
+bool parcAtomicUint32_IsValid(const PARCAtomicUint32 *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCAtomicUint32` 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
+ * {
+ * PARCAtomicUint32 *a = parcAtomicUint32_Create();
+ *
+ * parcAtomicUint32_Release(&a);
+ * }
+ * @endcode
+ */
+void parcAtomicUint32_Release(PARCAtomicUint32 **instancePtr);
+
+/**
+ * Get the current value of the given `PARCAtomicUint32` instance.
+ *
+ * @param [in] instance A pointer to a valid `PARCAtomicUint32` instance.
+ *
+ * @return the current value of the given `PARCAtomicUint32` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint32 *instance = parcAtomicUint32_Create(7);
+ *
+ * uint32_t value = parcAtomicUint32_GetValue(instance);
+ *
+ * parcAtomicUint32_Release(&instance);
+ * }
+ * @endcode
+ */
+uint32_t parcAtomicUint32_GetValue(const PARCAtomicUint32 *instance);
+#endif
diff --git a/libparc/parc/concurrent/parc_AtomicUint64.c b/libparc/parc/concurrent/parc_AtomicUint64.c
new file mode 100755
index 00000000..35d5cf66
--- /dev/null
+++ b/libparc/parc/concurrent/parc_AtomicUint64.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/concurrent/parc_AtomicUint64.h>
+
+struct PARCAtomicUint64 {
+ uint64_t value;
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_t mutex;
+#endif
+};
+
+static void
+_parcAtomicUint64_Finalize(PARCAtomicUint64 **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCAtomicUint64 pointer.");
+
+ parcAtomicUint64_OptionalAssertValid((*instancePtr));
+
+ /* cleanup the instance fields here */
+}
+
+parcObject_ImplementAcquire(parcAtomicUint64, PARCAtomicUint64);
+
+parcObject_ImplementRelease(parcAtomicUint64, PARCAtomicUint64);
+
+parcObject_ExtendPARCObject(PARCAtomicUint64, _parcAtomicUint64_Finalize, parcAtomicUint64_Copy, NULL, parcAtomicUint64_Equals, parcAtomicUint64_Compare, parcAtomicUint64_HashCode, NULL);
+
+
+void
+parcAtomicUint64_AssertValid(const PARCAtomicUint64 *instance)
+{
+ assertTrue(parcAtomicUint64_IsValid(instance),
+ "PARCAtomicUint64 is not valid.");
+}
+
+PARCAtomicUint64 *
+parcAtomicUint64_Create(uint64_t value)
+{
+ PARCAtomicUint64 *result = parcObject_CreateAndClearInstance(PARCAtomicUint64);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_init(&result->mutex, NULL);
+ result->value = value;
+#else
+ *result = value;
+#endif
+
+ return result;
+}
+
+int
+parcAtomicUint64_Compare(const PARCAtomicUint64 *instance, const PARCAtomicUint64 *other)
+{
+ int64_t comparison = parcAtomicUint64_GetValue(instance) - parcAtomicUint64_GetValue(other);
+
+ int result = 0;
+ if (comparison < 0) {
+ result = -1;
+ } else if (comparison > 0) {
+ result = 1;
+ }
+
+ return result;
+}
+
+PARCAtomicUint64 *
+parcAtomicUint64_Copy(const PARCAtomicUint64 *original)
+{
+ PARCAtomicUint64 *result = parcAtomicUint64_Create(parcAtomicUint64_GetValue(original));
+
+ return result;
+}
+
+bool
+parcAtomicUint64_Equals(const PARCAtomicUint64 *x, const PARCAtomicUint64 *y)
+{
+ bool result = false;
+
+ result = parcAtomicUint64_GetValue(x) == parcAtomicUint64_GetValue(y);
+
+ return result;
+}
+
+PARCHashCode
+parcAtomicUint64_HashCode(const PARCAtomicUint64 *instance)
+{
+ PARCHashCode result = (PARCHashCode) parcAtomicUint64_GetValue(instance);
+
+ return result;
+}
+
+bool
+parcAtomicUint64_IsValid(const PARCAtomicUint64 *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+uint64_t
+parcAtomicUint64_GetValue(const PARCAtomicUint64 *instance)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ return instance->value;
+#else
+ return *instance;
+#endif
+}
+
+uint64_t
+parcAtomicUint64_AddImpl(PARCAtomicUint64 *value, uint64_t addend)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ value->value += addend;
+ uint64_t result = value->value;
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ return __sync_add_and_fetch(value, addend);
+#endif
+}
+
+uint64_t
+parcAtomicUint64_SubtractImpl(PARCAtomicUint64 *value, uint64_t subtrahend)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ value->value -= subtrahend;
+ uint64_t result = value->value;
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ return __sync_sub_and_fetch(value, subtrahend);
+#endif
+}
+
+bool
+parcAtomicUint64_CompareAndSwapImpl(PARCAtomicUint64 *value, uint64_t predicate, uint64_t newValue)
+{
+ bool result = false;
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ if (value->value == predicate) {
+ value->value = newValue;
+ result = true;
+ }
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ result = __sync_bool_compare_and_swap(value, predicate, newValue);
+#endif
+ return result;
+}
diff --git a/libparc/parc/concurrent/parc_AtomicUint64.h b/libparc/parc/concurrent/parc_AtomicUint64.h
new file mode 100755
index 00000000..a6ac3ec1
--- /dev/null
+++ b/libparc/parc/concurrent/parc_AtomicUint64.h
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_AtomicUint64.h
+ * @ingroup threading
+ * @brief An atomically updated 64-bit unsigned integer.
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_AtomicUint64
+#define PARCLibrary_parc_AtomicUint64
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_JSON.h>
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+#include <pthread.h>
+struct PARCAtomicUint64;
+typedef struct PARCAtomicUint64 PARCAtomicUint64;
+#else
+typedef uint64_t PARCAtomicUint64;
+#endif
+
+
+PARCAtomicUint64 *parcAtomicInteger_CreateUint64(uint64_t value);
+
+uint64_t parcAtomicUint64_AddImpl(PARCAtomicUint64 *value, uint64_t addend);
+
+uint64_t parcAtomicUint64_SubtractImpl(PARCAtomicUint64 *value, uint64_t subtrahend);
+
+bool parcAtomicUint64_CompareAndSwapImpl(PARCAtomicUint64 *value, uint64_t predicate, uint64_t newValue);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+
+#define parcAtomicUint64_Add parcAtomicUint64_AddImpl
+
+#define parcAtomicUint64_Subtract parcAtomicUint64_SubtractImpl
+
+#define parcAtomicUint64_CompareAndSwap parcAtomicUint64_CompareAndSwapImpl
+
+#else
+
+#define parcAtomicUint64_Add(_atomic_uint64_, _addend_) \
+ __sync_add_and_fetch(_atomic_uint64_, _addend_)
+
+#define parcAtomicUint64_Subtract(_atomic_uint64_, _subtrahend_) \
+ __sync_sub_and_fetch(_atomic_uint64_, _subtrahend_)
+
+#define parcAtomicUint64_CompareAndSwap(_atomic_uint64_, _predicate_, _newValue_) \
+ __sync_bool_compare_and_swap(_atomic_uint64_, _predicate_, _newValue_)
+#endif
+
+#define parcAtomicUint64_Increment(_atomic_uint64_) parcAtomicUint64_Add(_atomic_uint64_, 1)
+#define parcAtomicUint64_Decrement(_atomic_uint64_) parcAtomicUint64_Subtract(_atomic_uint64_, 1)
+
+/**
+ * Increase the number of references to a `PARCAtomicUint64` instance.
+ *
+ * Note that new `PARCAtomicUint64` is not created,
+ * only that the given `PARCAtomicUint64` reference count is incremented.
+ * Discard the reference by invoking `parcAtomicUint64_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint64 instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ *
+ * PARCAtomicUint64 *b = parcAtomicUint64_Acquire();
+ *
+ * parcAtomicUint64_Release(&a);
+ * parcAtomicUint64_Release(&b);
+ * }
+ * @endcode
+ */
+PARCAtomicUint64 *parcAtomicUint64_Acquire(const PARCAtomicUint64 *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcAtomicUint64_OptionalAssertValid(_instance_)
+#else
+# define parcAtomicUint64_OptionalAssertValid(_instance_) parcAtomicUint64_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCAtomicUint64` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint64 instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ *
+ * parcAtomicUint64_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcAtomicUint64_Release(&b);
+ * }
+ * @endcode
+ */
+void parcAtomicUint64_AssertValid(const PARCAtomicUint64 *instance);
+
+/**
+ * Create an instance of PARCAtomicUint64
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCAtomicUint64 instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ *
+ * parcAtomicUint64_Release(&b);
+ * }
+ * @endcode
+ */
+PARCAtomicUint64 *parcAtomicUint64_Create(uint64_t);
+
+/**
+ * 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 PARCAtomicUint64 instance.
+ * @param [in] other A pointer to a valid PARCAtomicUint64 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
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ * PARCAtomicUint64 *b = parcAtomicUint64_Create();
+ *
+ * if (parcAtomicUint64_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcAtomicUint64_Release(&a);
+ * parcAtomicUint64_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcAtomicUint64_Equals
+ */
+int parcAtomicUint64_Compare(const PARCAtomicUint64 *instance, const PARCAtomicUint64 *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 PARCAtomicUint64 instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCAtomicUint64` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ *
+ * PARCAtomicUint64 *copy = parcAtomicUint64_Copy(&b);
+ *
+ * parcAtomicUint64_Release(&b);
+ * parcAtomicUint64_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCAtomicUint64 *parcAtomicUint64_Copy(const PARCAtomicUint64 *original);
+
+/**
+ * Determine if two `PARCAtomicUint64` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCAtomicUint64` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcAtomicUint64_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcAtomicUint64_Equals(x, y)` must return true if and only if
+ * `parcAtomicUint64_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcAtomicUint64_Equals(x, y)` returns true and
+ * `parcAtomicUint64_Equals(y, z)` returns true,
+ * then `parcAtomicUint64_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcAtomicUint64_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcAtomicUint64_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCAtomicUint64 instance.
+ * @param [in] y A pointer to a valid PARCAtomicUint64 instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ * PARCAtomicUint64 *b = parcAtomicUint64_Create();
+ *
+ * if (parcAtomicUint64_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcAtomicUint64_Release(&a);
+ * parcAtomicUint64_Release(&b);
+ * }
+ * @endcode
+ * @see parcAtomicUint64_HashCode
+ */
+bool parcAtomicUint64_Equals(const PARCAtomicUint64 *x, const PARCAtomicUint64 *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 parcAtomicUint64_Equals} method,
+ * then calling the {@link parcAtomicUint64_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 parcAtomicUint64_Equals} function,
+ * then calling the `parcAtomicUint64_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint64 instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ *
+ * PARCHashCode hashValue = parcAtomicUint64_HashCode(buffer);
+ * parcAtomicUint64_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcAtomicUint64_HashCode(const PARCAtomicUint64 *instance);
+
+/**
+ * Determine if an instance of `PARCAtomicUint64` 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 PARCAtomicUint64 instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ *
+ * if (parcAtomicUint64_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcAtomicUint64_Release(&b);
+ * }
+ * @endcode
+ */
+bool parcAtomicUint64_IsValid(const PARCAtomicUint64 *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCAtomicUint64` 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
+ * {
+ * PARCAtomicUint64 *a = parcAtomicUint64_Create();
+ *
+ * parcAtomicUint64_Release(&a);
+ * }
+ * @endcode
+ */
+void parcAtomicUint64_Release(PARCAtomicUint64 **instancePtr);
+
+/**
+ * Get the current value of the given `PARCAtomicUint64` instance.
+ *
+ * @param [in] instance A pointer to a valid `PARCAtomicUint64` instance.
+ *
+ * @return the current value of the given `PARCAtomicUint64` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ *
+ * uint64_t value = parcAtomicUint64_GetValue(instance);
+ *
+ * parcAtomicUint64_Release(&instance);
+ * }
+ * @endcode
+ */
+uint64_t parcAtomicUint64_GetValue(const PARCAtomicUint64 *instance);
+#endif
diff --git a/libparc/parc/concurrent/parc_AtomicUint8.c b/libparc/parc/concurrent/parc_AtomicUint8.c
new file mode 100755
index 00000000..59a3d865
--- /dev/null
+++ b/libparc/parc/concurrent/parc_AtomicUint8.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/concurrent/parc_AtomicUint8.h>
+
+struct PARCAtomicUint8 {
+ uint8_t value;
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_t mutex;
+#endif
+};
+
+static void
+_parcAtomicUint8_Finalize(PARCAtomicUint8 **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCAtomicUint8 pointer.");
+
+ parcAtomicUint8_OptionalAssertValid((*instancePtr));
+
+ /* cleanup the instance fields here */
+}
+
+parcObject_ImplementAcquire(parcAtomicUint8, PARCAtomicUint8);
+
+parcObject_ImplementRelease(parcAtomicUint8, PARCAtomicUint8);
+
+parcObject_ExtendPARCObject(PARCAtomicUint8, _parcAtomicUint8_Finalize, parcAtomicUint8_Copy, NULL, parcAtomicUint8_Equals, parcAtomicUint8_Compare, parcAtomicUint8_HashCode, NULL);
+
+
+void
+parcAtomicUint8_AssertValid(const PARCAtomicUint8 *instance)
+{
+ assertTrue(parcAtomicUint8_IsValid(instance),
+ "PARCAtomicUint8 is not valid.");
+}
+
+PARCAtomicUint8 *
+parcAtomicUint8_Create(uint8_t value)
+{
+ PARCAtomicUint8 *result = parcObject_CreateAndClearInstance(PARCAtomicUint8);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_init(&result->mutex, NULL);
+ result->value = value;
+#else
+ *result = value;
+#endif
+
+ return result;
+}
+
+int
+parcAtomicUint8_Compare(const PARCAtomicUint8 *instance, const PARCAtomicUint8 *other)
+{
+ int8_t comparison = parcAtomicUint8_GetValue(instance) - parcAtomicUint8_GetValue(other);
+
+ int result = 0;
+ if (comparison < 0) {
+ result = -1;
+ } else if (comparison > 0) {
+ result = 1;
+ }
+
+ return result;
+}
+
+PARCAtomicUint8 *
+parcAtomicUint8_Copy(const PARCAtomicUint8 *original)
+{
+ PARCAtomicUint8 *result = parcAtomicUint8_Create(parcAtomicUint8_GetValue(original));
+
+ return result;
+}
+
+bool
+parcAtomicUint8_Equals(const PARCAtomicUint8 *x, const PARCAtomicUint8 *y)
+{
+ bool result = false;
+
+ result = parcAtomicUint8_GetValue(x) == parcAtomicUint8_GetValue(y);
+
+ return result;
+}
+
+PARCHashCode
+parcAtomicUint8_HashCode(const PARCAtomicUint8 *instance)
+{
+ PARCHashCode result = (uint32_t) parcAtomicUint8_GetValue(instance);
+
+ return result;
+}
+
+bool
+parcAtomicUint8_IsValid(const PARCAtomicUint8 *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+uint8_t
+parcAtomicUint8_GetValue(const PARCAtomicUint8 *instance)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ return instance->value;
+#else
+ return *instance;
+#endif
+}
+
+uint8_t
+parcAtomicUint8_AddImpl(PARCAtomicUint8 *value, uint8_t addend)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ value->value += addend;
+ uint8_t result = value->value;
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ return __sync_add_and_fetch(value, addend);
+#endif
+}
+
+uint8_t
+parcAtomicUint8_SubtractImpl(PARCAtomicUint8 *value, uint8_t subtrahend)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ value->value -= subtrahend;
+ uint8_t result = value->value;
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ return __sync_sub_and_fetch(value, subtrahend);
+#endif
+}
+
+bool
+parcAtomicUint8_CompareAndSwapImpl(PARCAtomicUint8 *value, uint8_t predicate, uint8_t newValue)
+{
+ bool result = false;
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&value->mutex);
+ if (value->value == predicate) {
+ value->value = newValue;
+ result = true;
+ }
+ pthread_mutex_unlock(&value->mutex);
+ return result;
+#else
+ result = __sync_bool_compare_and_swap(value, predicate, newValue);
+#endif
+ return result;
+}
diff --git a/libparc/parc/concurrent/parc_AtomicUint8.h b/libparc/parc/concurrent/parc_AtomicUint8.h
new file mode 100755
index 00000000..7434b93d
--- /dev/null
+++ b/libparc/parc/concurrent/parc_AtomicUint8.h
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_AtomicUint8.h
+ * @ingroup threading
+ * @brief An atomically updated 8-bit unsigned integer.
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_AtomicUint8
+#define PARCLibrary_parc_AtomicUint8
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_JSON.h>
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+#include <pthread.h>
+struct PARCAtomicUint8;
+typedef struct PARCAtomicUint8 PARCAtomicUint8;
+#else
+typedef uint8_t PARCAtomicUint8;
+#endif
+
+
+PARCAtomicUint8 *parcAtomicInteger_CreateUint8(uint8_t value);
+
+uint8_t parcAtomicUint8_AddImpl(PARCAtomicUint8 *value, uint8_t addend);
+
+uint8_t parcAtomicUint8_SubtractImpl(PARCAtomicUint8 *value, uint8_t subtrahend);
+
+bool parcAtomicUint8_CompareAndSwapImpl(PARCAtomicUint8 *value, uint8_t predicate, uint8_t newValue);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+
+#define parcAtomicUint8_Add parcAtomicUint8_AddImpl
+
+#define parcAtomicUint8_Subtract parcAtomicUint8_SubtractImpl
+
+#define parcAtomicUint8_CompareAndSwap parcAtomicUint8_CompareAndSwapImpl
+
+#else
+
+#define parcAtomicUint8_Add(_atomic_uint8_, _addend_) \
+ __sync_add_and_fetch(_atomic_uint8_, _addend_)
+
+#define parcAtomicUint8_Subtract(_atomic_uint8_, _subtrahend_) \
+ __sync_sub_and_fetch(_atomic_uint8_, _subtrahend_)
+
+#define parcAtomicUint8_CompareAndSwap(_atomic_uint8_, _predicate_, _newValue_) \
+ __sync_bool_compare_and_swap(_atomic_uint8_, _predicate_, _newValue_)
+#endif
+
+#define parcAtomicUint8_Increment(_atomic_uint8_) parcAtomicUint8_Add(_atomic_uint8_, 1)
+#define parcAtomicUint8_Decrement(_atomic_uint8_) parcAtomicUint8_Subtract(_atomic_uint8_, 1)
+
+/**
+ * Increase the number of references to a `PARCAtomicUint8` instance.
+ *
+ * Note that new `PARCAtomicUint8` is not created,
+ * only that the given `PARCAtomicUint8` reference count is incremented.
+ * Discard the reference by invoking `parcAtomicUint8_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint8 instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ *
+ * PARCAtomicUint8 *b = parcAtomicUint8_Acquire();
+ *
+ * parcAtomicUint8_Release(&a);
+ * parcAtomicUint8_Release(&b);
+ * }
+ * @endcode
+ */
+PARCAtomicUint8 *parcAtomicUint8_Acquire(const PARCAtomicUint8 *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcAtomicUint8_OptionalAssertValid(_instance_)
+#else
+# define parcAtomicUint8_OptionalAssertValid(_instance_) parcAtomicUint8_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCAtomicUint8` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint8 instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ *
+ * parcAtomicUint8_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcAtomicUint8_Release(&b);
+ * }
+ * @endcode
+ */
+void parcAtomicUint8_AssertValid(const PARCAtomicUint8 *instance);
+
+/**
+ * Create an instance of PARCAtomicUint8
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCAtomicUint8 instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ *
+ * parcAtomicUint8_Release(&b);
+ * }
+ * @endcode
+ */
+PARCAtomicUint8 *parcAtomicUint8_Create(uint8_t);
+
+/**
+ * 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 PARCAtomicUint8 instance.
+ * @param [in] other A pointer to a valid PARCAtomicUint8 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
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ * PARCAtomicUint8 *b = parcAtomicUint8_Create();
+ *
+ * if (parcAtomicUint8_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcAtomicUint8_Release(&a);
+ * parcAtomicUint8_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcAtomicUint8_Equals
+ */
+int parcAtomicUint8_Compare(const PARCAtomicUint8 *instance, const PARCAtomicUint8 *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 PARCAtomicUint8 instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCAtomicUint8` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ *
+ * PARCAtomicUint8 *copy = parcAtomicUint8_Copy(&b);
+ *
+ * parcAtomicUint8_Release(&b);
+ * parcAtomicUint8_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCAtomicUint8 *parcAtomicUint8_Copy(const PARCAtomicUint8 *original);
+
+/**
+ * Determine if two `PARCAtomicUint8` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCAtomicUint8` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcAtomicUint8_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcAtomicUint8_Equals(x, y)` must return true if and only if
+ * `parcAtomicUint8_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcAtomicUint8_Equals(x, y)` returns true and
+ * `parcAtomicUint8_Equals(y, z)` returns true,
+ * then `parcAtomicUint8_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcAtomicUint8_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcAtomicUint8_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCAtomicUint8 instance.
+ * @param [in] y A pointer to a valid PARCAtomicUint8 instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ * PARCAtomicUint8 *b = parcAtomicUint8_Create();
+ *
+ * if (parcAtomicUint8_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcAtomicUint8_Release(&a);
+ * parcAtomicUint8_Release(&b);
+ * }
+ * @endcode
+ * @see parcAtomicUint8_HashCode
+ */
+bool parcAtomicUint8_Equals(const PARCAtomicUint8 *x, const PARCAtomicUint8 *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 parcAtomicUint8_Equals} method,
+ * then calling the {@link parcAtomicUint8_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 parcAtomicUint8_Equals} function,
+ * then calling the `parcAtomicUint8_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCAtomicUint8 instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ *
+ * PARCHashCode hashValue = parcAtomicUint8_HashCode(buffer);
+ * parcAtomicUint8_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcAtomicUint8_HashCode(const PARCAtomicUint8 *instance);
+
+/**
+ * Determine if an instance of `PARCAtomicUint8` 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 PARCAtomicUint8 instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ *
+ * if (parcAtomicUint8_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcAtomicUint8_Release(&b);
+ * }
+ * @endcode
+ */
+bool parcAtomicUint8_IsValid(const PARCAtomicUint8 *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCAtomicUint8` 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
+ * {
+ * PARCAtomicUint8 *a = parcAtomicUint8_Create();
+ *
+ * parcAtomicUint8_Release(&a);
+ * }
+ * @endcode
+ */
+void parcAtomicUint8_Release(PARCAtomicUint8 **instancePtr);
+
+/**
+ * Get the current value of the given `PARCAtomicUint8` instance.
+ *
+ * @param [in] instance A pointer to a valid `PARCAtomicUint8` instance.
+ *
+ * @return the current value of the given `PARCAtomicUint8` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+ *
+ * uint8_t value = parcAtomicUint8_GetValue(instance);
+ *
+ * parcAtomicUint8_Release(&instance);
+ * }
+ * @endcode
+ */
+uint8_t parcAtomicUint8_GetValue(const PARCAtomicUint8 *instance);
+#endif
diff --git a/libparc/parc/concurrent/parc_FutureTask.c b/libparc/parc/concurrent/parc_FutureTask.c
new file mode 100755
index 00000000..0ba2c224
--- /dev/null
+++ b/libparc/parc/concurrent/parc_FutureTask.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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_Execution.h>
+
+#include <parc/concurrent/parc_FutureTask.h>
+
+struct PARCFutureTask {
+ void *(*function)(PARCFutureTask *task, void *parameter);
+ void *parameter;
+ void *result;
+ bool isRunning;
+ bool isDone;
+ bool isCancelled;
+};
+
+static void
+_parcFutureTask_Initialise(PARCFutureTask *futureTask)
+{
+ futureTask->result = NULL;
+ futureTask->isDone = false;
+ futureTask->isCancelled = false;
+ futureTask->isRunning = false;
+}
+
+static bool
+_parcFutureTask_Destructor(PARCFutureTask **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCFutureTask pointer.");
+ PARCFutureTask *task = *instancePtr;
+
+ if (parcObject_IsInstanceOf(task->parameter, &PARCObject_Descriptor)) {
+ parcObject_Release(&task->parameter);
+ }
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcFutureTask, PARCFutureTask);
+
+parcObject_ImplementRelease(parcFutureTask, PARCFutureTask);
+
+parcObject_Override(PARCFutureTask, PARCObject,
+ .isLockable = true,
+ .destructor = (PARCObjectDestructor *) _parcFutureTask_Destructor,
+ .copy = (PARCObjectCopy *) parcFutureTask_Copy,
+ .toString = (PARCObjectToString *) parcFutureTask_ToString,
+ .equals = (PARCObjectEquals *) parcFutureTask_Equals,
+ .compare = (PARCObjectCompare *) parcFutureTask_Compare,
+ .hashCode = (PARCObjectHashCode *) parcFutureTask_HashCode,
+ .display = (PARCObjectDisplay *) parcFutureTask_Display);
+
+void
+parcFutureTask_AssertValid(const PARCFutureTask *task)
+{
+ assertTrue(parcFutureTask_IsValid(task),
+ "PARCFutureTask is not valid.");
+}
+
+PARCFutureTask *
+parcFutureTask_Create(void *(*function)(PARCFutureTask *task, void *parameter), void *parameter)
+{
+ PARCFutureTask *result = parcObject_CreateInstance(PARCFutureTask);
+
+ if (parcObject_IsInstanceOf(parameter, &PARCObject_Descriptor)) {
+ parameter = parcObject_Acquire(parameter);
+ }
+
+ if (result != NULL) {
+ result->function = function;
+ result->parameter = parameter;
+ _parcFutureTask_Initialise(result);
+ }
+
+ return result;
+}
+
+int
+parcFutureTask_Compare(const PARCFutureTask *instance, const PARCFutureTask *other)
+{
+ int result = 0;
+
+ return result;
+}
+
+PARCFutureTask *
+parcFutureTask_Copy(const PARCFutureTask *original)
+{
+ PARCFutureTask *result = parcFutureTask_Create(original->function, original->parameter);
+
+ return result;
+}
+
+void
+parcFutureTask_Display(const PARCFutureTask *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCFutureTask@%p {", instance);
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcFutureTask_Equals(const PARCFutureTask *x, const PARCFutureTask *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (x->function == y->function) {
+ if (x->parameter == y->parameter) {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcFutureTask_HashCode(const PARCFutureTask *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+parcFutureTask_IsValid(const PARCFutureTask *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcFutureTask_ToJSON(const PARCFutureTask *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ if (result != NULL) {
+ }
+
+ return result;
+}
+
+char *
+parcFutureTask_ToString(const PARCFutureTask *instance)
+{
+ char *result = parcMemory_Format("PARCFutureTask@%p\n", instance);
+
+ return result;
+}
+
+bool
+parcFutureTask_Cancel(PARCFutureTask *task, bool mayInterruptIfRunning)
+{
+ bool result = false;
+
+ if (parcObject_Lock(task)) {
+ if (task->isRunning) {
+ if (mayInterruptIfRunning) {
+ printf("Interrupting a running task is not implemented yet.\n");
+ }
+ result = false;
+ } else {
+ task->isCancelled = true;
+ task->isDone = true;
+ parcObject_Notify(task);
+ result = true;
+ }
+
+ parcObject_Unlock(task);
+ }
+
+ return result;
+}
+
+PARCFutureTaskResult
+parcFutureTask_Get(const PARCFutureTask *futureTask, const PARCTimeout *timeout)
+{
+ PARCFutureTaskResult result;
+
+ result.execution = PARCExecution_Timeout;
+ result.value = 0;
+
+ if (parcTimeout_IsImmediate(timeout)) {
+ if (futureTask->isDone) {
+ result.execution = PARCExecution_OK;
+ result.value = futureTask->result;
+ }
+ } else {
+ result.execution = PARCExecution_Interrupted;
+ result.value = 0;
+
+ parcObject_Lock(futureTask);
+ while (!futureTask->isDone) {
+ if (parcTimeout_IsNever(timeout)) {
+ parcObject_Wait(futureTask);
+ result.execution = PARCExecution_OK;
+ result.value = futureTask->result;
+ break;
+ } else {
+ if (parcObject_WaitFor(futureTask, parcTimeout_InNanoSeconds(timeout))) {
+ result.execution = PARCExecution_OK;
+ result.value = futureTask->result;
+ break;
+ }
+ }
+ }
+ parcObject_Unlock(futureTask);
+ }
+
+ return result;
+}
+
+bool
+parcFutureTask_IsCancelled(const PARCFutureTask *task)
+{
+ return task->isCancelled;
+}
+
+bool
+parcFutureTask_IsDone(const PARCFutureTask *task)
+{
+ return task->isDone;
+}
+
+static void *
+_parcFutureTask_Execute(PARCFutureTask *task)
+{
+ task->isRunning = true;
+ void *result = task->function(task, task->parameter);
+ task->isRunning = false;
+
+ return result;
+}
+
+void *
+parcFutureTask_Run(PARCFutureTask *task)
+{
+ if (parcFutureTask_Lock(task)) {
+ if (!task->isCancelled) {
+ task->result = _parcFutureTask_Execute(task);
+ task->isDone = true;
+ parcFutureTask_Notify(task);
+ }
+ parcFutureTask_Unlock(task);
+ } else {
+ trapCannotObtainLock("Cannot lock PARCFutureTask");
+ }
+ return task->result;
+}
+
+bool
+parcFutureTask_RunAndReset(PARCFutureTask *task)
+{
+ bool result = false;
+
+ if (parcObject_Lock(task)) {
+ if (!task->isCancelled) {
+ _parcFutureTask_Execute(task);
+ parcFutureTask_Reset(task);
+ result = true;
+ }
+ parcFutureTask_Unlock(task);
+ } else {
+ trapCannotObtainLock("Cannot lock PARCFutureTask");
+ }
+
+ return result;
+}
+
+void
+parcFutureTask_Reset(PARCFutureTask *task)
+{
+ _parcFutureTask_Initialise(task);
+}
diff --git a/libparc/parc/concurrent/parc_FutureTask.h b/libparc/parc/concurrent/parc_FutureTask.h
new file mode 100755
index 00000000..9a5776c5
--- /dev/null
+++ b/libparc/parc/concurrent/parc_FutureTask.h
@@ -0,0 +1,657 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_FutureTask.h
+ * @ingroup threading
+ * @brief An encapsulated, asynchronous computation.
+ *
+ * This type associates a function and a pointer to data and provides the functionality
+ * to invoke the function supplying the given pointer to data and returning the result.
+ *
+ * The operations of invoking the function and collecting its return value may be asynchronous from each other
+ * in that an attempting to fetch the return value before the function has been invoked
+ * will cause the calling thread to block until the function has been invoked and run to completion.
+ * This enables the use of PARCFutureTask in a work queue, or thread pool where tasks are run asynchronously
+ * from each other and from an originating thread.
+ *
+ * Each instance of the type may be cancelled,
+ * inhibiting a future invocation of the associated function.
+ *
+ * Typical use is a one time invocation of the associated function, induced by the `parcFutureTask_Get`,
+ * but invoking `parcFutureTask_GetAndReset` invokes the associated function and resets the task to the initial state,
+ * permitting a future call to `parcFutureTask_Get` or `parcFutureTask_GetAndReset` the run the associated function again.
+ *
+ */
+#ifndef PARCLibrary_parc_FutureTask
+#define PARCLibrary_parc_FutureTask
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/concurrent/parc_Timeout.h>
+#include <parc/algol/parc_Execution.h>
+
+struct PARCFutureTask;
+typedef struct PARCFutureTask PARCFutureTask;
+
+typedef struct PARCFutureTaskResult {
+ void *value;
+ PARCExecution *execution;
+} PARCFutureTaskResult;
+
+/**
+ * Increase the number of references to a `PARCFutureTask` instance.
+ *
+ * Note that new `PARCFutureTask` is not created,
+ * only that the given `PARCFutureTask` reference count is incremented.
+ * Discard the reference by invoking `parcFutureTask_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCFutureTask instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * PARCFutureTask *b = parcFutureTask_Acquire();
+ *
+ * parcFutureTask_Release(&a);
+ * parcFutureTask_Release(&b);
+ * }
+ * @endcode
+ */
+PARCFutureTask *parcFutureTask_Acquire(const PARCFutureTask *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcFutureTask_OptionalAssertValid(_instance_)
+#else
+# define parcFutureTask_OptionalAssertValid(_instance_) parcFutureTask_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCFutureTask` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCFutureTask instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * parcFutureTask_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcFutureTask_Release(&b);
+ * }
+ * @endcode
+ */
+void parcFutureTask_AssertValid(const PARCFutureTask *instance);
+
+/**
+ * Create an instance of `PARCFutureTask`
+ *
+ * If the parameter is an instance of `PARCObject` a reference to the object will
+ * be created and ultimately released via `parcFutureTask_Release`
+ *
+ * @param [in] function A pointer to a function to call.
+ * @param [in] parameter A pointer that will be passed to the function when invoked.
+ *
+ * @return non-NULL A pointer to a valid `PARCFutureTask` instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create(function, parameter);
+ *
+ * parcFutureTask_Release(&a);
+ * }
+ * @endcode
+ */
+PARCFutureTask *parcFutureTask_Create(void *(*runnable)(PARCFutureTask *task, void *parameter), void *parameter);
+
+/**
+ * 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 PARCFutureTask instance.
+ * @param [in] other A pointer to a valid PARCFutureTask 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
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ * PARCFutureTask *b = parcFutureTask_Create();
+ *
+ * if (parcFutureTask_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcFutureTask_Release(&a);
+ * parcFutureTask_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcFutureTask_Equals
+ */
+int parcFutureTask_Compare(const PARCFutureTask *instance, const PARCFutureTask *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 PARCFutureTask instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCFutureTask` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * PARCFutureTask *copy = parcFutureTask_Copy(&b);
+ *
+ * parcFutureTask_Release(&b);
+ * parcFutureTask_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCFutureTask *parcFutureTask_Copy(const PARCFutureTask *original);
+
+/**
+ * Print a human readable representation of the given `PARCFutureTask`.
+ *
+ * @param [in] instance A pointer to a valid `PARCFutureTask` instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * parcFutureTask_Display(a, 0);
+ *
+ * parcFutureTask_Release(&a);
+ * }
+ * @endcode
+ */
+void parcFutureTask_Display(const PARCFutureTask *instance, int indentation);
+
+/**
+ * Determine if two `PARCFutureTask` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCFutureTask` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcFutureTask_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcFutureTask_Equals(x, y)` must return true if and only if
+ * `parcFutureTask_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcFutureTask_Equals(x, y)` returns true and
+ * `parcFutureTask_Equals(y, z)` returns true,
+ * then `parcFutureTask_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcFutureTask_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcFutureTask_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCFutureTask instance.
+ * @param [in] y A pointer to a valid PARCFutureTask instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ * PARCFutureTask *b = parcFutureTask_Create();
+ *
+ * if (parcFutureTask_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcFutureTask_Release(&a);
+ * parcFutureTask_Release(&b);
+ * }
+ * @endcode
+ * @see parcFutureTask_HashCode
+ */
+bool parcFutureTask_Equals(const PARCFutureTask *x, const PARCFutureTask *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 parcFutureTask_Equals} method,
+ * then calling the {@link parcFutureTask_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 parcFutureTask_Equals} function,
+ * then calling the `parcFutureTask_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCFutureTask instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * PARCHashCode hashValue = parcFutureTask_HashCode(buffer);
+ * parcFutureTask_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcFutureTask_HashCode(const PARCFutureTask *instance);
+
+/**
+ * Determine if an instance of `PARCFutureTask` 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 PARCFutureTask instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * if (parcFutureTask_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcFutureTask_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcFutureTask_IsValid(const PARCFutureTask *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCFutureTask` 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
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * parcFutureTask_Release(&a);
+ * }
+ * @endcode
+ */
+void parcFutureTask_Release(PARCFutureTask **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCFutureTask 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
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * PARCJSON *json = parcFutureTask_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcFutureTask_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcFutureTask_ToJSON(const PARCFutureTask *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCFutureTask`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCFutureTask 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
+ * {
+ * PARCFutureTask *a = parcFutureTask_Create();
+ *
+ * char *string = parcFutureTask_ToString(a);
+ *
+ * parcFutureTask_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcFutureTask_Display
+ */
+char *parcFutureTask_ToString(const PARCFutureTask *instance);
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcFutureTask_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] object A pointer to a valid PARCFutureTask instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcFutureTask_Lock(object)) {
+ * parcFutureTask_Notify(object);
+ * parcFutureTask_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotify(parcFutureTask, PARCFutureTask);
+
+/**
+ * Wakes up all threads that are waiting on the given object's lock.
+ *
+ * A thread waits on an object by calling one of the wait methods, `parcFutureTask_Wait`, `parcFutureTask_WaitFor`, `parcFutureTask_WaitUntil`.
+ * The awakened threads will proceed after the current thread relinquishes the lock on the given object.
+ * The awakened threads will compete in the usual manner with any other threads that might be actively competing
+ * to synchronize on this object.
+ * Awakened threads have no priority between them in being the next thread to lock this object.
+ *
+ * This method can only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid `PARCFutureTask` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcFutureTask_Lock(object)) {
+ * parcFutureTask_NotifyAll(object);
+ * parcFutureTask_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotifyAll(parcFutureTask, PARCFutureTask);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the parcFutureTask_Notify() function on the same object.
+ * *
+ * @param [in] object A pointer to a valid `PARCFutureTask` instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcFutureTask_Wait(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementWait(parcFutureTask, PARCFutureTask);
+
+/**
+ * Obtain the lock on the given `PARCFutureTask` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] object A pointer to a valid `PARCFutureTask` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, or the `PARCFutureTask` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcFutureTask_Lock(object)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementLock(parcFutureTask, PARCFutureTask);
+
+/**
+ * Try to obtain the advisory lock on the given PARCFutureTask instance.
+ *
+ * Once the lock is obtained, the caller must release the lock as soon as possible.
+ *
+ * @param [in] object A pointer to a valid PARCFutureTask instance.
+ *
+ * @return true The PARCFutureTask is locked.
+ * @return false The PARCFutureTask is unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcFutureTask_TryLock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementTryLock(parcFutureTask, PARCFutureTask);
+
+/**
+ * Try to unlock the advisory lock on the given `PARCFutureTask` instance.
+ *
+ * @param [in] object A pointer to a valid `PARCFutureTask` instance.
+ *
+ * @return true The `PARCFutureTask` was locked and now is unlocked.
+ * @return false The `PARCFutureTask` was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcFutureTask_Unlock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementUnlock(parcFutureTask, PARCFutureTask);
+
+/**
+ * Determine if the advisory lock on the given `PARCFutureTask` instance is locked.
+ *
+ * @param [in] object A pointer to a valid `PARCFutureTask` instance.
+ *
+ * @return true The `PARCFutureTask` is locked.
+ * @return false The `PARCFutureTask` is unlocked.
+ * Example:
+ * @code
+ * {
+ * if (parcFutureTask_IsLocked(object)) {
+ * ...
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementIsLocked(parcFutureTask, PARCFutureTask);
+
+/**
+ * Attempt to cancel the execution of this task.
+ *
+ * This will return `false` if the task is already done or has already been cancelled.
+ * Otherswise, if this task has not started when `parcFutureTask_Cancel` is called, this task will never run.
+ *
+ * If the task is already running, the boolean `mayInterruptIfRunning` may cause the task to be interrupted,
+ * otherwise this function will have no effect.
+ *
+ * After this function returns, subsequent calls to `parcFutureTask_IsDone` will always return true.
+ * Subsequent calls to `parcFutureTask_isCancelled` will always return true if this function returned true.
+ *
+ * @param [in] object A pointer to a valid `PARCFutureTask` instance.
+ *
+ * @return true The task was cancelled.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcFutureTask_Cancel(PARCFutureTask *task, bool mayInterruptIfRunning);
+
+/**
+ * Waits if necessary for at most the given time for the computation to complete, and then retrieves its result, if available.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFutureTaskResult parcFutureTask_Get(const PARCFutureTask *futureTask, const PARCTimeout *timeout);
+
+/**
+ * Returns true if this task was cancelled before it completed normally.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcFutureTask_IsCancelled(const PARCFutureTask *futureTask);
+
+/**
+ * Returns true if this task completed.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcFutureTask_IsDone(const PARCFutureTask *futureTask);
+
+/**
+ * Sets this Future to the result of its computation unless it has been cancelled.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return The result returned by the task function.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void *parcFutureTask_Run(PARCFutureTask *futureTask);
+
+/**
+ * Executes the computation without setting its result, and then resets this future to initial state, failing to do so if the computation encounters an exception or is cancelled.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return true The task was executed.
+ * @retval false The task was not executed because it was previously completed, or it was cancelled.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcFutureTask_RunAndReset(PARCFutureTask *futureTask);
+
+/**
+ * Reset the given PARCFutureTask to the intial state, a subsequent ecutes the computation without setting its result, and then resets this future to initial state, failing to do so if the computation encounters an exception or is cancelled.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return true The task was successfully run
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcFutureTask_Reset(PARCFutureTask *task);
+#endif
diff --git a/libparc/parc/concurrent/parc_Lock.c b/libparc/parc/concurrent/parc_Lock.c
new file mode 100755
index 00000000..d510b5ed
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Lock.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <pthread.h>
+#include <errno.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/concurrent/parc_Lock.h>
+
+struct PARCLock {
+ pthread_mutex_t lock;
+ pthread_mutexattr_t lockAttributes;
+ pthread_cond_t notification;
+ bool locked;
+
+ bool notified;
+};
+
+static void
+_parcLock_Finalize(PARCLock **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCLock pointer.");
+
+ parcLock_OptionalAssertValid(*instancePtr);
+
+ /* cleanup the instance fields here */
+}
+
+parcObject_ImplementAcquire(parcLock, PARCLock);
+
+parcObject_ImplementRelease(parcLock, PARCLock);
+
+parcObject_ExtendPARCObject(PARCLock, _parcLock_Finalize, NULL, parcLock_ToString, NULL, NULL, NULL, NULL);
+
+void
+parcLock_AssertValid(const PARCLock *instance)
+{
+ assertTrue(parcLock_IsValid(instance),
+ "PARCLock is not valid.");
+}
+
+PARCLock *
+parcLock_Create(void)
+{
+ PARCLock *result = parcObject_CreateInstance(PARCLock);
+
+ pthread_mutexattr_init(&result->lockAttributes);
+ pthread_mutexattr_settype(&result->lockAttributes, PTHREAD_MUTEX_ERRORCHECK);
+
+ pthread_mutex_init(&result->lock, &result->lockAttributes);
+
+ result->locked = false;
+ pthread_cond_init(&result->notification, NULL);
+ result->notified = false;
+ return result;
+}
+
+void
+parcLock_Display(const PARCLock *lock, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCLock@%p {", lock);
+ parcDisplayIndented_PrintLine(indentation + 1, ".locked=%s", lock->locked ? "true" : "false");
+
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcLock_IsValid(const PARCLock *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCBufferComposer *
+parcLock_BuildString(const PARCLock *lock, PARCBufferComposer *composer)
+{
+ parcBufferComposer_Format(composer, "lock{.state=%s }", lock->locked ? "true" : "false");
+
+ return composer;
+}
+
+char *
+parcLock_ToString(const PARCLock *lock)
+{
+ char *result = NULL;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ if (composer != NULL) {
+ parcLock_BuildString(lock, composer);
+ result = parcBufferComposer_ToString(composer);
+ parcBufferComposer_Release(&composer);
+ }
+
+ return result;
+}
+
+bool
+parcLock_Unlock(PARCLock *lock)
+{
+ bool result = false;
+
+ parcLock_OptionalAssertValid(lock);
+
+ if (lock->locked) {
+ result = (pthread_mutex_unlock(&lock->lock) == 0);
+ }
+
+ return result;
+}
+
+bool
+parcLock_Lock(PARCLock *lock)
+{
+ bool result = false;
+
+ parcLock_OptionalAssertValid(lock);
+
+ int error = pthread_mutex_lock(&lock->lock);
+
+ if (error == 0) {
+ lock->locked = true;
+ result = true;
+ errno = 0;
+ } else {
+ errno = error;
+ }
+
+ return result;
+}
+
+bool
+parcLock_TryLock(PARCLock *lock)
+{
+ bool result = false;
+
+ parcLock_OptionalAssertValid(lock);
+
+ result = (pthread_mutex_trylock(&lock->lock) == 0);
+ if (result) {
+ lock->locked = true;
+ }
+
+ return result;
+}
+
+bool
+parcLock_IsLocked(const PARCLock *lock)
+{
+ parcLock_OptionalAssertValid(lock);
+
+ return lock->locked;
+}
+
+void
+parcLock_Wait(PARCLock *lock)
+{
+ parcLock_OptionalAssertValid(lock);
+
+ trapUnexpectedStateIf(lock->locked == false,
+ "You must Lock the object before calling parcLock_Wait");
+
+ lock->notified = false;
+ while (lock->notified == false) {
+ pthread_cond_wait(&lock->notification, &lock->lock);
+ }
+}
+
+void
+parcLock_Notify(PARCLock *lock)
+{
+ parcLock_OptionalAssertValid(lock);
+
+ trapUnexpectedStateIf(lock->locked == false,
+ "You must Lock the object before calling parcLock_Notify");
+
+ lock->notified = true;
+ pthread_cond_signal(&lock->notification);
+}
+
diff --git a/libparc/parc/concurrent/parc_Lock.h b/libparc/parc/concurrent/parc_Lock.h
new file mode 100755
index 00000000..ecba1c19
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Lock.h
@@ -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.
+ */
+
+/**
+ * @file parc_Lock.h
+ * @ingroup threading
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_Lock
+#define PARCLibrary_parc_Lock
+#include <stdbool.h>
+
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_JSON.h>
+
+struct PARCLock;
+typedef struct PARCLock PARCLock;
+
+/**
+ * Increase the number of references to a `PARCLock` instance.
+ *
+ * Note that new `PARCLock` is not created,
+ * only that the given `PARCLock` reference count is incremented.
+ * Discard the reference by invoking `parcLock_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCLock instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLock *a = parcLock_Create();
+ *
+ * PARCLock *b = parcLock_Acquire();
+ *
+ * parcLock_Release(&a);
+ * parcLock_Release(&b);
+ * }
+ * @endcode
+ */
+PARCLock *parcLock_Acquire(const PARCLock *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcLock_OptionalAssertValid(_instance_)
+#else
+# define parcLock_OptionalAssertValid(_instance_) parcLock_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCLock` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCLock instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLock *a = parcLock_Create();
+ *
+ * parcLock_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcLock_Release(&b);
+ * }
+ * @endcode
+ */
+void parcLock_AssertValid(const PARCLock *instance);
+
+/**
+ * Create an instance of PARCLock
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCLock instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLock *a = parcLock_Create();
+ *
+ * parcLock_Release(&a);
+ * }
+ * @endcode
+ */
+PARCLock *parcLock_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 PARCLock instance.
+ * @param [in] other A pointer to a valid PARCLock 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
+ * {
+ * PARCLock *a = parcLock_Create();
+ * PARCLock *b = parcLock_Create();
+ *
+ * if (parcLock_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcLock_Release(&a);
+ * parcLock_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcLock_Equals
+ */
+int parcLock_Compare(const PARCLock *instance, const PARCLock *other);
+
+/**
+ * Print a human readable representation of the given `PARCLock`.
+ *
+ * @param [in] instance A pointer to a valid PARCLock instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLock *a = parcLock_Create();
+ *
+ * parcLock_Display(a, 0);
+ *
+ * parcLock_Release(&a);
+ * }
+ * @endcode
+ */
+void parcLock_Display(const PARCLock *instance, int indentation);
+
+/**
+ * Determine if an instance of `PARCLock` 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 PARCLock instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLock *a = parcLock_Create();
+ *
+ * if (parcLock_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcLock_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcLock_IsValid(const PARCLock *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCLock` 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
+ * {
+ * PARCLock *a = parcLock_Create();
+ *
+ * parcLock_Release(&a);
+ * }
+ * @endcode
+ */
+void parcLock_Release(PARCLock **instancePtr);
+
+/**
+ * Append a representation of the specified `PARCLock` instance to the given `PARCBufferComposer`.
+ *
+ * @param [in] name A pointer to a `PARCLock` 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();
+ *
+ * parcLock_BuildString(instance, result);
+ *
+ * char *string = parcBufferComposer_ToString(result);
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate(string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcLock_BuildString(const PARCLock *name, PARCBufferComposer *composer);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCLock`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCLock 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
+ * {
+ * PARCLock *a = parcLock_Create();
+ *
+ * char *string = parcLock_ToString(a);
+ *
+ * parcLock_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcLock_Display
+ */
+char *parcLock_ToString(const PARCLock *instance);
+
+/**
+ * Obtain the lock on the given `PARCLock` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] lock A pointer to a valid `PARCLock` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, or the `PARCLock` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcLock_Lock(lock)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+bool parcLock_Lock(PARCLock *lock);
+
+/**
+ * Try to obtain the advisory lock on the given `PARCObject` instance.
+ *
+ * Once the lock is obtained, the caller must release the lock via `parcObject_Unlock`.
+ *
+ * @param [in] lock A pointer to a valid `PARCObject` instance.
+ *
+ * @return true The `PARCObject` is locked.
+ * @return false The `PARCObject` is unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * while (parcLock_TryLock(object))
+ * ;
+ * }
+ * @endcode
+ */
+bool parcLock_TryLock(PARCLock *lock);
+
+/**
+ * Try to unlock the advisory lock on the given PARCObject instance.
+ *
+ * @param [in] lock A pointer to a valid PARCObject instance.
+ *
+ * @return true The PARCObject was locked and now is unlocked.
+ * @return false The PARCObject was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcLock_Unlock(object);
+ * }
+ * @endcode
+ */
+bool parcLock_Unlock(PARCLock *lock);
+
+/**
+ * Determine if the advisory lock on the given PARCObject instance is locked.
+ *
+ * @param [in] lock A pointer to a valid PARCObject instance.
+ *
+ * @return true The PARCObject is locked.
+ * @return false The PARCObject is unlocked.
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcLock_IsLocked(const PARCLock *lock);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the parcObject_Notify() function on the same object.
+ *
+ * The calling thread must own this object's lock.
+ * The calling thread will release ownership of this lock and wait until another thread invokes `parcObject_Notify`
+ * on the same object. The original calling thread then re-obtains ownership of the lock and resumes execution.
+ *
+ * This function must only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] lock A pointer to a valid PARCObject instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcObject_Wait(object);
+ * }
+ * @endcode
+ */
+void parcLock_Wait(PARCLock *lock);
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcObject_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] lock A pointer to a valid `PARCObject` instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcObject_Notify(object);
+ * }
+ * @endcode
+ */
+void parcLock_Notify(PARCLock *lock);
+#endif
diff --git a/libparc/parc/concurrent/parc_Notifier.c b/libparc/parc/concurrent/parc_Notifier.c
new file mode 100755
index 00000000..6cba9147
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Notifier.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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/concurrent/parc_Notifier.h>
+#include <parc/algol/parc_Object.h>
+
+#ifdef __GNUC__
+#define ATOMIC_ADD_AND_FETCH(ptr, increment) __sync_add_and_fetch(ptr, increment)
+#define ATOMIC_BOOL_CAS(ptr, oldvalue, newvalue) __sync_bool_compare_and_swap(ptr, oldvalue, newvalue)
+#define ATOMIC_FETCH(ptr) ATOMIC_ADD_AND_FETCH(ptr, 0)
+#define ATOMIC_SET(ptr, oldvalue, newvalue) ATOMIC_BOOL_CAS(ptr, oldvalue, newvalue)
+#else
+#error "Only GNUC supported, we need atomic operations"
+#endif
+
+struct parc_notifier {
+ volatile int paused;
+
+ // If the notifications are paused and there is an event,
+ // we indicate that we skipped a notify
+ volatile int skippedNotify;
+
+#define PARCNotifierWriteFd 1
+#define PARCNotifierReadFd 0
+ int fds[2];
+};
+
+static void
+_parcNotifier_Finalize(PARCNotifier **notifierPtr)
+{
+ PARCNotifier *notifier = *notifierPtr;
+
+ close(notifier->fds[0]);
+ close(notifier->fds[1]);
+}
+
+parcObject_ExtendPARCObject(PARCNotifier, _parcNotifier_Finalize, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static bool
+_parcNotifier_MakeNonblocking(PARCNotifier *notifier)
+{
+ // set the read side to be non-blocking
+ int flags = fcntl(notifier->fds[PARCNotifierReadFd], F_GETFL, 0);
+ if (flags == 0) {
+ if (fcntl(notifier->fds[PARCNotifierReadFd], F_SETFL, flags | O_NONBLOCK) == 0) {
+ return true;
+ }
+ }
+ perror("fcntl error");
+ return false;
+}
+
+PARCNotifier *
+parcNotifier_Create(void)
+{
+ PARCNotifier *notifier = parcObject_CreateInstance(PARCNotifier);
+ if (notifier) {
+ notifier->paused = false;
+ notifier->skippedNotify = false;
+
+ int failure = pipe(notifier->fds);
+ assertFalse(failure, "Error on pipe: %s", strerror(errno));
+
+ if (!_parcNotifier_MakeNonblocking(notifier)) {
+ parcObject_Release((void **) &notifier);
+ }
+ }
+
+ return notifier;
+}
+
+parcObject_ImplementAcquire(parcNotifier, PARCNotifier);
+
+parcObject_ImplementRelease(parcNotifier, PARCNotifier);
+
+
+int
+parcNotifier_Socket(PARCNotifier *notifier)
+{
+ return notifier->fds[PARCNotifierReadFd];
+}
+
+bool
+parcNotifier_Notify(PARCNotifier *notifier)
+{
+ if (ATOMIC_BOOL_CAS(&notifier->paused, 0, 1)) {
+ // old value was "0" so we need to send a notification
+ uint8_t one = 1;
+ ssize_t written;
+ do {
+ written = write(notifier->fds[PARCNotifierWriteFd], &one, 1);
+ assertTrue(written >= 0, "Error writing to socket %d: %s", notifier->fds[PARCNotifierWriteFd], strerror(errno));
+ } while (written == 0);
+
+ return true;
+ } else {
+ // we're paused, so count up the pauses
+ ATOMIC_ADD_AND_FETCH(&notifier->skippedNotify, 1);
+ return false;
+ }
+}
+
+void
+parcNotifier_PauseEvents(PARCNotifier *notifier)
+{
+ // reset the skipped counter so we count from now until the StartEvents call
+ notifier->skippedNotify = 0;
+ ATOMIC_BOOL_CAS(&notifier->paused, 0, 1);
+
+ // now clear out the socket
+ uint8_t buffer[16];
+ while (read(notifier->fds[PARCNotifierReadFd], &buffer, 16) > 0) {
+ ;
+ }
+}
+
+void
+parcNotifier_StartEvents(PARCNotifier *notifier)
+{
+ ATOMIC_BOOL_CAS(&notifier->paused, 1, 0);
+ if (notifier->skippedNotify) {
+ // we missed some notifications, so re-signal ourself
+ parcNotifier_Notify(notifier);
+ }
+}
diff --git a/libparc/parc/concurrent/parc_Notifier.h b/libparc/parc/concurrent/parc_Notifier.h
new file mode 100755
index 00000000..44eda3b5
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Notifier.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Notifier.h
+ * @ingroup threading
+ * @brief Inter-thread/process notification
+ *
+ * A 1-way event notification system. The first call to parcNotifier_SetEvent() will post an
+ * event to the parcNotifier_Socket(). Subsequent calls will not post an event. When the
+ * event consumer is ready to handle the event, it calls parcNotifier_PauseEvents(), then processes
+ * the events, then calls parcNotifier_StartEvents().
+ *
+ * @code
+ * {
+ * // example code on the event consumer's side
+ * struct pollfd pfd;
+ * pfd.fd = parcNotifier_Socket(notifier);
+ * pfd.events = POLLIN;
+ *
+ * while(1) {
+ * if (poll(&fd, 1, -1)) {
+ * parcNotifier_PauseEvents(notifier);
+ *
+ * // process events, such as reading from a RingBuffer
+ * void *data;
+ * while (parcRingBuffer1x1_Get(ring, &data)) {
+ * // handle data
+ * }
+ *
+ * parcNotifier_StartEvents(notifier);
+ * }
+ * }
+ * }
+ * @endcode
+ *
+ * The notification system guarantees that no notifications will be missed. However, there may be
+ * extra notifications. For example, in the above code, if an event is signalled between the
+ * parcNotifier_PauseEvents() and parcRingBuffer1x1_Get() calls, then on parcNotifier_StartEvents()
+ * an extra event will be triggered, even though the ring buffer is empty.
+ *
+ */
+
+#ifndef libparc_parc_Notifier_h
+#define libparc_parc_Notifier_h
+
+#include <stdbool.h>
+
+struct parc_notifier;
+typedef struct parc_notifier PARCNotifier;
+
+/**
+ * Create a new instance of `PARCNotifier`
+ *
+ * @return A new instance of `PARCNotifier`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCNotifier *parcNotifier_Create(void);
+
+/**
+ * Increase the number of references to a `PARCNotifier`.
+ *
+ * Note that new `PARCNotifier` is not created,
+ * only that the given `PARCNotifier` reference count is incremented.
+ * Discard the reference by invoking `parcNotifier_Release`.
+ *
+ * @param [in] instance A pointer to a `PARCNotifier` instance.
+ *
+ * @return The input `PARCNotifier` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCNotifier *a = parcNotifier_Create(...);
+ *
+ * PARCNotifier *b = parcNotifier_Acquire(a);
+ *
+ * parcNotifier_Release(&a);
+ * parcNotifier_Release(&b);
+ * }
+ * @endcode
+ */
+PARCNotifier *parcNotifier_Acquire(const PARCNotifier *notifier);
+
+/**
+ * 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] instancePtr A pointer to a pointer to the instance to release, which will be set to NULL.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCNotifier *a = parcNotifier_Create(...);
+ *
+ * parcNotifier_Release(&a);
+ * }
+ * @endcode
+ */
+void parcNotifier_Release(PARCNotifier **notifier);
+
+/**
+ * Fetches the notification socket
+ *
+ * The notification socket may be used in select() or poll() or similar
+ * functions. You should not read or write to the socket.
+ *
+ * @param [in] notifier The instance of `PARCNotifier`
+ *
+ * @return The notification socket.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int parcNotifier_Socket(PARCNotifier *notifier);
+
+/**
+ * Sends a notification to the notifier socket
+ *
+ * @param [in] notifier The instance of `PARCNotifier`
+ *
+ * @return True is successsful, else false.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcNotifier_Notify(PARCNotifier *notifier);
+
+/**
+ * Pause the event stream of the Notifier
+ *
+ * @param [in] notifier The instance of `PARCNotifier`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcNotifier_PauseEvents(PARCNotifier *notifier);
+
+/**
+ * Restart the event stream of the Notifier
+ *
+ * @param [in] notifier The instance of `PARCNotifier`
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcNotifier_StartEvents(PARCNotifier *notifier);
+#endif // libparc_parc_Notifier_h
diff --git a/libparc/parc/concurrent/parc_RingBuffer.c b/libparc/parc/concurrent/parc_RingBuffer.c
new file mode 100755
index 00000000..9492ae92
--- /dev/null
+++ b/libparc/parc/concurrent/parc_RingBuffer.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.
+ */
+
+/**
+ * This is a facade over the 1x1 or NxM ring buffers.
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <errno.h>
+#include <string.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <LongBow/runtime.h>
+
+#include <parc/concurrent/parc_RingBuffer.h>
+
+struct parc_ringbuffer {
+ PARCRingBufferInterface *interface;
+};
+
+static void
+_parcRingBuffer_Finalize(PARCRingBuffer **pointer)
+{
+ PARCRingBuffer *buffer = *pointer;
+ buffer->interface->release(&(buffer->interface));
+}
+
+parcObject_ExtendPARCObject(PARCRingBuffer, _parcRingBuffer_Finalize, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCRingBuffer *
+parcRingBuffer_Create(PARCRingBufferInterface *interface)
+{
+ PARCRingBuffer *ring = parcObject_CreateInstance(PARCRingBuffer);
+ ring->interface = interface;
+ return ring;
+}
+
+parcObject_ImplementAcquire(parcRingBuffer, PARCRingBuffer);
+
+parcObject_ImplementRelease(parcRingBuffer, PARCRingBuffer);
+
+bool
+parcRingBuffer_Put(PARCRingBuffer *ring, void *data)
+{
+ return ring->interface->put(ring->interface->instance, data);
+}
+
+bool
+parcRingBuffer_Get(PARCRingBuffer *ring, void **outputDataPtr)
+{
+ return ring->interface->put(ring->interface->instance, outputDataPtr);
+}
+
+uint32_t
+parcRingBuffer_Remaining(PARCRingBuffer *ring)
+{
+ return ring->interface->remaining(ring->interface->instance);
+}
diff --git a/libparc/parc/concurrent/parc_RingBuffer.h b/libparc/parc/concurrent/parc_RingBuffer.h
new file mode 100755
index 00000000..211f044e
--- /dev/null
+++ b/libparc/parc/concurrent/parc_RingBuffer.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_RingBuffer.h
+ * @ingroup threading
+ * @brief A thread-safe ring buffer.
+ *
+ * A fixed size, thread safe ring buffer. It can have multiple producers and multiple
+ * consumers. All exclusion is done inside the ring buffer.
+ *
+ * This is a non-blocking data structure.
+ *
+ * If the user knows there is only one producer and one consumer, you can create the ring buffer with
+ * `parcRingBuffer_CreateSingleProducerSingleConsumer`. Such a ring buffer can have at most 2 references.
+ *
+ */
+
+#ifndef libparc_parc_RingBuffer_h
+#define libparc_parc_RingBuffer_h
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct parc_ringbuffer;
+typedef struct parc_ringbuffer PARCRingBuffer;
+
+/**< Will be called for each data item on destroy */
+typedef void (RingBufferEntryDestroyer)(void **entryPtr);
+
+struct parc_ringbuffer_impl;
+typedef struct parc_ringbuffer_interface PARCRingBufferInterface;
+
+struct parc_ringbuffer_interface {
+ void *instance;
+ void * (*acquire)(PARCRingBufferInterface *ring);
+ void (*release)(PARCRingBufferInterface **ring);
+ bool (*put)(PARCRingBufferInterface *ring, void *data);
+ bool (*get)(PARCRingBufferInterface *ring, void *outputDataPtr);
+ bool (*remaining)(PARCRingBufferInterface *ring);
+};
+
+/**
+ * Creates a ring buffer of the given size, which must be a power of 2.
+ *
+ * The ring buffer can store up to (elements-1) items in the buffer. The buffer can
+ * be shared between multiple producers and consumers. Each of them should be
+ * given out from a call to {@link parcRingBuffer_Acquire} to create reference counted
+ * copies.
+ *
+ * The reference count is "1" on return.
+ *
+ * @param [in] interface A pointer to the underlying instance and the interface functions for acquire,
+ * release,put,get,and remaining.
+ *
+ * @return non-null An pointer to a new allocated `PARCRingBuffer`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCRingBuffer *parcRingBuffer_Create(PARCRingBufferInterface *interface);
+
+/**
+ * Acquire a new reference to an instance of `PARCRingBuffer`.
+ *
+ * A RING WITHOUT LOCKS CAN ONLY HAVE 2 REFERENCES.
+ * The reference count to the instance is incremented.
+ *
+ * @param [in] ring The instance of `PARCRingBuffer` to which to refer.
+ *
+ * @return The same value as the input parameter @p ring
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+
+PARCRingBuffer *parcRingBuffer_Acquire(const PARCRingBuffer *ring);
+
+/**
+ * Releases a reference. The buffer will be destroyed after the last release.
+ *
+ * If the destroyer was specified on create, it will be called on each entry in the buffer
+ * when the buffer is destroyed.
+ *
+ * @param [in,out] ringPtr The pointer to the pointer of the `PARCRingBuffer` to be destroyed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcRingBuffer_Release(PARCRingBuffer **ringPtr);
+
+/**
+ * Non-blocking attempt to put item on ring. May return false if ring is full.
+ *
+ * @param [in,out] ring The instance of `PARCRingBuffer` to modify'
+ * @param [in] data A pointer to teh data to put on the ring.
+ *
+ * @return true Data was put on the queue
+ * @return false Would have blocked, the queue was full
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcRingBuffer_Put(PARCRingBuffer *ring, void *data);
+
+/**
+ * Gets the next item off the ring, or returns false if would have blocked.
+ *
+ * Non-blocking, gets an item off the ring, or returns false if would block
+ *
+ * @param [in] ring The pointer to the `PARCRingBuffer`
+ * @param [out] outputDataPtr The output pointer
+ *
+ * @return true Data returned in the output argument
+ * @return false Ring is empty, no data returned.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcRingBuffer_Get(PARCRingBuffer *ring, void **outputDataPtr);
+
+/**
+ * Returns the remaining capacity of the ring
+ *
+ * Returns the remaining capacity of the ring. This does not guarantee the next
+ * Put will not block, as other producers might consumer the space between calls.
+ *
+ * @param [in] ring The pointer to the `PARCRingBuffer`
+ *
+ * @return The uint32_t remaining capacity of the ring.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint32_t parcRingBuffer_Remaining(PARCRingBuffer *ring);
+#endif // libparc_parc_RingBuffer_h
diff --git a/libparc/parc/concurrent/parc_RingBuffer_1x1.c b/libparc/parc/concurrent/parc_RingBuffer_1x1.c
new file mode 100755
index 00000000..a023f4d7
--- /dev/null
+++ b/libparc/parc/concurrent/parc_RingBuffer_1x1.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.
+ */
+
+/**
+ * A thread-safe fixed size ring buffer.
+ *
+ * A single-producer/single-consumer version is lock-free, along the lines of Lamport, "Proving the
+ * Correctness of Multiprocess Programs," IEEE Trans on Software Engineering 3(2), Mar 1977, which
+ * is based on reading/writing native types upto the data bus width being atomic operations.
+ *
+ * It can hold (elements-1) data items. elements must be a power of 2.
+ *
+ * The writer_head is where the next element should be inserted. The reader_tail is where the next element
+ * should be read.
+ *
+ * All index variables are unbounded uint32_t. This means they just keep counting up. To get the actual
+ * index in the ring, we mask with (elements-1). For example, a ring with 16 elements will be masked with
+ * 0x0000000F. We call this the "ring_mask".
+ *
+ * Because we never let the writer_head and reader_tail differ by more than (elements-1), this technique of
+ * masking works just the same as taking the modulus. There's no problems at the uint32_t wraparound either.
+ * The only math operation we are doing is "+1" which works just fine to wrap a uint32_t.
+ *
+ * Let's look at some exampls. I'm going to use a uint16_t so its easier to write the numbers. Let's assume
+ * that the ring size is 16, so the first ring is (0 - 15).
+ * head tail
+ * initialize 0 0
+ * put x 3 3 0
+ * get x 2 3 2
+ * put x 13 16 2
+ * put x 1 17 2
+ * put x 1 blocks # (0x11 + 1) & 0x0F == tail & 0x0F
+ * get x 14 17 16
+ * get x 1 17 17 # ring is now empty
+ * ...
+ * empty 65534 65534 # 0xFFFE 0xFFFE masked = 14 14
+ * put x1 65535 65534 # 0xFFFF 0xFFFE masked = 15 14
+ * put x1 0 65534 # 0x0000 0xFFFE masked = 0 14
+ * ...
+ *
+ * The number of remaining available items is (ring_mask + reader_tail - writer_head) & ring_mask.
+ * head tail remaining
+ * initialize 0 0 15 + 0 - 0 = 15
+ * put x 3 3 0 15 + 0 - 3 = 12
+ * get x 2 3 2
+ * put x 13 16 2 15 + 2 - 16 = 1
+ * put x 1 17 2 15 + 2 - 17 = 0
+ * put x 1 blocks
+ * get x 14 17 16 15 + 16 - 17 = 14
+ * get x 1 17 17 15 + 17 - 17 = 15
+ * ...
+ * empty 65534 65534 15 + 65534 - 65534 = 13 - 65534 = 13 - (-2) = 15
+ * put x1 65535 65534 15 + 65534 - 65535 = 13 - 65535 = 13 - (-1) = 14
+ * put x1 0 65534 15 + 65534 - 0 = 13 - 65535 = 13 - ( 0) = 13
+ * ...
+ *
+ * If (writer_head + 1) & ring_mask == reader_tail, then the ring is full.
+ * If writer_head == reader_tail, then the ring is empty.
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <LongBow/runtime.h>
+
+#include <parc/concurrent/parc_RingBuffer_1x1.h>
+
+#ifdef __GNUC__
+
+// on x86 or x86_64, simple assignment will work
+#if (__x86_64__ || __i386__)
+#define ATOMIC_ADD_AND_FETCH(ptr, increment) __sync_add_and_fetch(ptr, increment)
+#define ATOMIC_BOOL_CAS(ptr, oldvalue, newvalue) __sync_bool_compare_and_swap(ptr, oldvalue, newvalue)
+#define ATOMIC_FETCH(ptr) *(ptr)
+#define ATOMIC_SET(ptr, oldvalue, newvalue) *(ptr) = newvalue
+#else
+#define ATOMIC_ADD_AND_FETCH(ptr, increment) __sync_add_and_fetch(ptr, increment)
+#define ATOMIC_BOOL_CAS(ptr, oldvalue, newvalue) __sync_bool_compare_and_swap(ptr, oldvalue, newvalue)
+#define ATOMIC_FETCH(ptr) ATOMIC_ADD_AND_FETCH(ptr, 0)
+#define ATOMIC_SET(ptr, oldvalue, newvalue) ATOMIC_BOOL_CAS(ptr, oldvalue, newvalue)
+#endif
+
+#else
+#error "Only GNUC supported, we need atomic operations"
+#endif
+
+struct parc_ringbuffer_1x1 {
+ // LP64 LP32
+ volatile uint32_t writer_head; // 0- 3 0
+ volatile uint32_t reader_tail; // 4- 7 4
+ uint32_t elements; // 8-11 8
+ uint32_t ring_mask; // 12-15 12
+
+ RingBufferEntryDestroyer *destroyer; // 16-23 16
+ void **buffer; // 24-31 24
+};
+
+static bool
+_isPowerOfTwo(uint32_t x)
+{
+ return ((x != 0) && !(x & (x - 1)));
+}
+
+static void
+_destroy(PARCRingBuffer1x1 **ringptr)
+{
+ PARCRingBuffer1x1 *ring = *ringptr;
+
+ if (ring->destroyer) {
+ void *ptr = NULL;
+ while (parcRingBuffer1x1_Get(ring, &ptr)) {
+ ring->destroyer(&ptr);
+ }
+ }
+ parcMemory_Deallocate((void **) &(ring->buffer));
+}
+
+parcObject_ExtendPARCObject(PARCRingBuffer1x1, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static PARCRingBuffer1x1 *
+_create(uint32_t elements, RingBufferEntryDestroyer *destroyer)
+{
+ PARCRingBuffer1x1 *ring = parcObject_CreateInstance(PARCRingBuffer1x1);
+ assertNotNull(ring, "parcObject_Create returned NULL");
+
+ ring->buffer = parcMemory_AllocateAndClear(sizeof(void *) * elements);
+ assertNotNull((ring->buffer), "parcMemory_AllocateAndClear() failed to allocate array of %u pointers", elements);
+
+ ring->writer_head = 0;
+ ring->reader_tail = 0;
+ ring->elements = elements;
+ ring->destroyer = destroyer;
+ ring->ring_mask = elements - 1;
+
+ return ring;
+}
+
+PARCRingBuffer1x1 *
+parcRingBuffer1x1_Create(uint32_t elements, RingBufferEntryDestroyer *destroyer)
+{
+ assertTrue(_isPowerOfTwo(elements), "Parameter elements must be a power of 2, got %u", elements);
+ return _create(elements, destroyer);
+}
+
+
+parcObject_ImplementAcquire(parcRingBuffer1x1, PARCRingBuffer1x1);
+
+parcObject_ImplementRelease(parcRingBuffer1x1, PARCRingBuffer1x1);
+
+/**
+ * Put is protected by the writer mutex. This means that the tail mutex could
+ * actually increase while this is happening. That's ok. Increasing the tail
+ * just means there is _more_ room in the ring. We only modify writer_head.
+ */
+bool
+parcRingBuffer1x1_Put(PARCRingBuffer1x1 *ring, void *data)
+{
+ // Our speculative operation
+ // The consumer modifies reader_tail, so make sure that's an atomic read.
+ // only the prodcuer modifies writer_head, so there's only us
+
+ uint32_t writer_head = ring->writer_head;
+ uint32_t reader_tail = ATOMIC_FETCH(&ring->reader_tail);
+
+ uint32_t writer_next = (writer_head + 1) & ring->ring_mask;
+
+ // ring is full
+ if (writer_next == reader_tail) {
+ return false;
+ }
+
+ assertNull(ring->buffer[writer_head], "Ring index %u is not null!", writer_head);
+ ring->buffer[writer_head] = data;
+
+ // we're using this just for atomic write to the integer
+ ATOMIC_SET(&ring->writer_head, writer_head, writer_next);
+
+ return true;
+}
+
+bool
+parcRingBuffer1x1_Get(PARCRingBuffer1x1 *ring, void **outputDataPtr)
+{
+ // do our speculative operation.
+ // The producer modifies writer_head, so make sure that's an atomic read.
+ // only the consumer modifies reader_tail, so there's only us
+
+ uint32_t writer_head = ATOMIC_FETCH(&ring->writer_head); // native type assignment is atomic
+ uint32_t reader_tail = ring->reader_tail;
+ uint32_t reader_next = (reader_tail + 1) & ring->ring_mask;
+
+ // ring is empty
+ if (writer_head == reader_tail) {
+ return false;
+ }
+
+ // now try to commit it
+ ATOMIC_SET(&ring->reader_tail, reader_tail, reader_next);
+
+ *outputDataPtr = ring->buffer[reader_tail];
+
+ // for sanity's sake
+ ring->buffer[reader_tail] = NULL;
+
+ return true;
+}
+
+uint32_t
+parcRingBuffer1x1_Remaining(PARCRingBuffer1x1 *ring)
+{
+ uint32_t writer_head = ATOMIC_FETCH(&ring->writer_head);
+ uint32_t reader_tail = ATOMIC_FETCH(&ring->reader_tail);
+
+ return (ring->ring_mask + reader_tail - writer_head) & ring->ring_mask;
+}
diff --git a/libparc/parc/concurrent/parc_RingBuffer_1x1.h b/libparc/parc/concurrent/parc_RingBuffer_1x1.h
new file mode 100755
index 00000000..4fd48e6b
--- /dev/null
+++ b/libparc/parc/concurrent/parc_RingBuffer_1x1.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 parc_RingBuffer_1x1.h
+ * @ingroup threading
+ * @brief A single producer, single consumer ring buffer
+ *
+ * This is useful for synchronizing two (and exactly two) threads in one direction. The
+ * implementation will use a lock-free algorithm.
+ *
+ * Complies with the PARCRingBuffer generic facade.
+ *
+ */
+
+#ifndef libparc_parc_RingBuffer_1x1_h
+#define libparc_parc_RingBuffer_1x1_h
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct parc_ringbuffer_1x1;
+typedef struct parc_ringbuffer_1x1 PARCRingBuffer1x1;
+
+/**< Will be called for each data item on destroy */
+typedef void (RingBufferEntryDestroyer)(void **entryPtr);
+
+/**
+ * Creates a ring buffer of the given size, which must be a power of 2.
+ *
+ * The ring buffer can store up to (elements-1) items in the buffer. The buffer can
+ * be shared between multiple producers and consumers. Each of them should be
+ * given out from a call to {@link parcRingBuffer_Acquire} to create reference counted
+ * copies.
+ *
+ * The reference count is "1" on return.
+ *
+ * @param [in] elements A power of 2, indicating the maximum size of the buffer.
+ * @param [in] destroyer Will be called for each ring entry when when the ring is destroyed. May be null.
+ *
+ * @return non-null An allocated ring buffer.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCRingBuffer1x1 *parcRingBuffer1x1_Create(uint32_t elements, RingBufferEntryDestroyer *destroyer);
+
+/**
+ * A reference counted copy of the buffer.
+ *
+ * A RING WITHOUT LOCKS CAN ONLY HAVE 2 REFERENCES.
+ *
+ * @param [in] ring The instance of `PARCRingBuffer1x1` to acquire.
+ *
+ * @return non-null A reference counted copy of the ring buffer.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCRingBuffer1x1 *parcRingBuffer1x1_Acquire(const PARCRingBuffer1x1 *ring);
+
+/**
+ * Releases a reference. The buffer will be destroyed after the last release.
+ *
+ * If the destroyer was specified on create, it will be called on each entry in the buffer
+ * when the buffer is destroyed.
+ *
+ * @param [in,out] ringPtr The pointer to the pointer of the `PARCRingBuffer1x1` to be released.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcRingBuffer1x1_Release(PARCRingBuffer1x1 **ringPtr);
+
+/**
+ * Non-blocking attempt to put item on ring. May return `false` if ring is full.
+ *
+ * @param [in,out] ring The instance of `PARCRingBuffer1x1` on which to put the @p data.
+ * @param [in] data The data to put on the @p ring.
+ *
+ * @return `true` Data was put on the queue
+ * @return `false` Would have blocked, the queue was full
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcRingBuffer1x1_Put(PARCRingBuffer1x1 *ring, void *data);
+
+/**
+ * Gets the next item off the ring, or returns false if would have blocked.
+ *
+ * Non-blocking, gets an item off the ring, or returns false if would block
+ *
+ * @param [in] ring The ring buffer
+ * @param [out] outputDataPtr The output pointer
+ *
+ * @return true Data returned in the output argument
+ * @return false Ring is empty, no data returned.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcRingBuffer1x1_Get(PARCRingBuffer1x1 *ring, void **outputDataPtr);
+
+/**
+ * Returns the remaining capacity of the ring
+ *
+ * Returns the remaining capacity of the ring. This does not guarantee the next
+ * Put will not block, as other producers might consumer the space between calls.
+ *
+ * @param [in] ring The instance of `PARCRingBuffer1x1` .
+ *
+ * @return The remaining capacity on the ring.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint32_t parcRingBuffer1x1_Remaining(PARCRingBuffer1x1 *ring);
+#endif // libparc_parc_RingBuffer_1x1_h
diff --git a/libparc/parc/concurrent/parc_RingBuffer_NxM.c b/libparc/parc/concurrent/parc_RingBuffer_NxM.c
new file mode 100755
index 00000000..15ec849b
--- /dev/null
+++ b/libparc/parc/concurrent/parc_RingBuffer_NxM.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.
+ */
+
+/**
+ * A thread-safe fixed size ring buffer.
+ *
+ * The multiple producer, multiple consumer version uses a pthread mutex around a NxM ring buffer.
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <errno.h>
+#include <string.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <LongBow/runtime.h>
+
+#include <parc/concurrent/parc_RingBuffer_1x1.h>
+#include <parc/concurrent/parc_RingBuffer_NxM.h>
+
+struct parc_ringbuffer_NxM {
+ PARCRingBuffer1x1 *onebyone;
+
+ // This protectes the overall data structure for Acquire and Release
+ pthread_mutex_t allocation_mutex;
+
+ pthread_mutex_t writer_mutex;
+ pthread_mutex_t reader_mutex;
+
+ RingBufferEntryDestroyer *destroyer;
+};
+
+/*
+ * Attemps a lock and returns false if we cannot get it.
+ *
+ * @endcode
+ */
+static bool
+_lock(pthread_mutex_t *mutex)
+{
+ int failure = pthread_mutex_lock(mutex);
+ assertFalse(failure, "Error locking mutex: (%d) %s\n", errno, strerror(errno));
+ return true;
+}
+
+static bool
+_unlock(pthread_mutex_t *mutex)
+{
+ int failure = pthread_mutex_unlock(mutex);
+ assertFalse(failure, "Error unlocking mutex: (%d) %s\n", errno, strerror(errno));
+ return true;
+}
+
+static void
+_destroy(PARCRingBufferNxM **ringptr)
+{
+ PARCRingBufferNxM *ring = *ringptr;
+
+ if (ring->destroyer) {
+ void *ptr = NULL;
+ while (parcRingBufferNxM_Get(ring, &ptr)) {
+ ring->destroyer(&ptr);
+ }
+ }
+ parcRingBuffer1x1_Release(&ring->onebyone);
+}
+
+
+parcObject_ExtendPARCObject(PARCRingBufferNxM, _destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static PARCRingBufferNxM *
+_create(uint32_t elements, RingBufferEntryDestroyer *destroyer)
+{
+ PARCRingBufferNxM *ring = parcObject_CreateInstance(PARCRingBufferNxM);
+ assertNotNull(ring, "parcObject_Create returned NULL");
+
+ ring->onebyone = parcRingBuffer1x1_Create(elements, destroyer);
+ ring->destroyer = destroyer;
+ pthread_mutex_init(&ring->allocation_mutex, NULL);
+ pthread_mutex_init(&ring->writer_mutex, NULL);
+ pthread_mutex_init(&ring->reader_mutex, NULL);
+ return ring;
+}
+
+PARCRingBufferNxM *
+parcRingBufferNxM_Create(uint32_t elements, RingBufferEntryDestroyer *destroyer)
+{
+ return _create(elements, destroyer);
+}
+
+PARCRingBufferNxM *
+parcRingBufferNxM_Acquire(PARCRingBufferNxM *ring)
+{
+ PARCRingBufferNxM *acquired;
+
+ _lock(&ring->allocation_mutex);
+ acquired = parcObject_Acquire(ring);
+ _unlock(&ring->allocation_mutex);
+
+ return acquired;
+}
+
+void
+parcRingBufferNxM_Release(PARCRingBufferNxM **ringPtr)
+{
+ PARCRingBufferNxM *ring = *ringPtr;
+ _lock(&ring->allocation_mutex);
+ parcObject_Release((void **) ringPtr);
+ _unlock(&ring->allocation_mutex);
+}
+
+/**
+ * Put is protected by the writer mutex. This means that the tail mutex could
+ * actually increase while this is happening. That's ok. Increasing the tail
+ * just means there is _more_ room in the ring. We only modify writer_head.
+ */
+bool
+parcRingBufferNxM_Put(PARCRingBufferNxM *ring, void *data)
+{
+ // **** LOCK
+ _lock(&ring->writer_mutex);
+ bool success = parcRingBuffer1x1_Put(ring->onebyone, data);
+ // **** UNLOCK
+ _unlock(&ring->writer_mutex);
+ return success;
+}
+
+bool
+parcRingBufferNxM_Get(PARCRingBufferNxM *ring, void **outputDataPtr)
+{
+ // **** LOCK
+ _lock(&ring->reader_mutex);
+ bool success = parcRingBuffer1x1_Get(ring->onebyone, outputDataPtr);
+ // **** UNLOCK
+ _unlock(&ring->reader_mutex);
+ return success;
+}
+
+uint32_t
+parcRingBufferNxM_Remaining(PARCRingBufferNxM *ring)
+{
+ _lock(&ring->writer_mutex);
+ _lock(&ring->reader_mutex);
+
+ uint32_t remaining = parcRingBuffer1x1_Remaining(ring->onebyone);
+
+ _unlock(&ring->reader_mutex);
+ _unlock(&ring->writer_mutex);
+
+ return remaining;
+}
diff --git a/libparc/parc/concurrent/parc_RingBuffer_NxM.h b/libparc/parc/concurrent/parc_RingBuffer_NxM.h
new file mode 100755
index 00000000..8cf38fdc
--- /dev/null
+++ b/libparc/parc/concurrent/parc_RingBuffer_NxM.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_RingBuffer_NxM.h
+ * @ingroup threading
+ * @brief A multiple producer, multiple consumer ring buffer
+ *
+ * This is useful for synchronizing one or more producers with one or more consumers.
+ * The implementation may use locks.
+ *
+ * Complies with the PARCRingBuffer generic facade.
+ *
+ */
+
+#ifndef libparc_parc_RingBuffer_NxM_h
+#define libparc_parc_RingBuffer_NxM_h
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <parc/concurrent/parc_RingBuffer_1x1.h>
+
+struct parc_ringbuffer_NxM;
+/**
+ * @typedef PARCRingBufferNxM
+ */
+typedef struct parc_ringbuffer_NxM PARCRingBufferNxM;
+
+/**
+ * Creates a ring buffer of the given size, which must be a power of 2.
+ *
+ * The ring buffer can store up to (elements-1) items in the buffer. The buffer can
+ * be shared between multiple producers and consumers. Each of them should be
+ * given out from a call to {@link parcRingBuffer_Acquire} to create reference counted
+ * copies.
+ *
+ * The reference count is "1" on return.
+ *
+ * @param [in] elements A power of 2, indicating the maximum size of the buffer.
+ * @param [in] destroyer Will be called for each ring entry when when the ring is destroyed. May be null.
+ *
+ * @return non-null An allocated ring buffer.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCRingBufferNxM *parcRingBufferNxM_Create(uint32_t elements, RingBufferEntryDestroyer *destroyer);
+
+/**
+ * A reference counted copy of the buffer.
+ *
+ * A RING WITHOUT LOCKS CAN ONLY HAVE 2 REFERENCES.
+ *
+ * @param [in] ring A pointer to the `PARCRingBufferNxM` to be acquired.
+ *
+ * @return non-null A reference counted copy of the ring buffer
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCRingBufferNxM *parcRingBufferNxM_Acquire(PARCRingBufferNxM *ring);
+
+/**
+ * Releases a reference. The buffer will be destroyed after the last release.
+ *
+ * If the destroyer was specified on create, it will be called on each entry in the buffer
+ * when the buffer is destroyed.
+ *
+ * @param [in,out] ringPtr A pointer to the pointer to the `PARCRingBufferNxM` to be released.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcRingBufferNxM_Release(PARCRingBufferNxM **ringPtr);
+
+/**
+ * Non-blocking attempt to put item on ring. May return false if ring is full.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in,out] ring A pointer to the `PARCRingBufferNxM` on which to put @p data.
+ * @param [in] data A pointer to data to put on @p ring.
+ *
+ * @return `true` Data was put on the queue
+ * @return `false` Would have blocked, the queue was full
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcRingBufferNxM_Put(PARCRingBufferNxM *ring, void *data);
+
+/**
+ * Gets the next item off the ring, or returns false if would have blocked.
+ *
+ * Non-blocking, gets an item off the ring, or returns false if would block
+ *
+ * @param [in] ring The ring buffer
+ * @param [out] outputDataPtr The output pointer
+ *
+ * @return `true` Data returned in the output argument
+ * @return `false` Ring is empty, no data returned.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcRingBufferNxM_Get(PARCRingBufferNxM *ring, void **outputDataPtr);
+
+/**
+ * Returns the remaining capacity of the ring
+ *
+ * Returns the remaining capacity of the ring. This does not guarantee the next
+ * Put will not block, as other producers might consumer the space between calls.
+ *
+ * @param [in] ring The ring buffer
+ *
+ * @return the remaining capacity of @p ring.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+uint32_t parcRingBufferNxM_Remaining(PARCRingBufferNxM *ring);
+#endif // libparc_parc_RingBuffer_NxM_h
diff --git a/libparc/parc/concurrent/parc_ScheduledTask.c b/libparc/parc/concurrent/parc_ScheduledTask.c
new file mode 100755
index 00000000..14c1d556
--- /dev/null
+++ b/libparc/parc/concurrent/parc_ScheduledTask.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 <sys/time.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 <parc/concurrent/parc_ScheduledTask.h>
+#include <parc/concurrent/parc_FutureTask.h>
+
+struct PARCScheduledTask {
+ PARCFutureTask *task;
+ uint64_t executionTime;
+};
+
+static bool
+_parcScheduledTask_Destructor(PARCScheduledTask **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCScheduledTask pointer.");
+ PARCScheduledTask *task = *instancePtr;
+
+ parcFutureTask_Release(&task->task);
+ return true;
+}
+
+parcObject_ImplementAcquire(parcScheduledTask, PARCScheduledTask);
+
+parcObject_ImplementRelease(parcScheduledTask, PARCScheduledTask);
+
+parcObject_Override(PARCScheduledTask, PARCObject,
+ .isLockable = true,
+ .destructor = (PARCObjectDestructor *) _parcScheduledTask_Destructor,
+ .copy = (PARCObjectCopy *) parcScheduledTask_Copy,
+ .toString = (PARCObjectToString *) parcScheduledTask_ToString,
+ .equals = (PARCObjectEquals *) parcScheduledTask_Equals,
+ .compare = (PARCObjectCompare *) parcScheduledTask_Compare,
+ .hashCode = (PARCObjectHashCode *) parcScheduledTask_HashCode,
+ .display = (PARCObjectDisplay *) parcScheduledTask_Display);
+
+void
+parcScheduledTask_AssertValid(const PARCScheduledTask *instance)
+{
+ assertTrue(parcScheduledTask_IsValid(instance),
+ "PARCScheduledTask is not valid.");
+}
+
+
+PARCScheduledTask *
+parcScheduledTask_Create(PARCFutureTask *task, uint64_t executionTime)
+{
+ PARCScheduledTask *result = parcObject_CreateInstance(PARCScheduledTask);
+
+ if (result != NULL) {
+ result->task = parcFutureTask_Acquire(task);
+ result->executionTime = executionTime;
+ }
+
+ return result;
+}
+
+int
+parcScheduledTask_Compare(const PARCScheduledTask *instance, const PARCScheduledTask *other)
+{
+ int result = 0;
+
+ return result;
+}
+
+PARCScheduledTask *
+parcScheduledTask_Copy(const PARCScheduledTask *original)
+{
+ PARCScheduledTask *result = parcScheduledTask_Create(original->task, original->executionTime);
+
+ return result;
+}
+
+void
+parcScheduledTask_Display(const PARCScheduledTask *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCScheduledTask@%p {", instance);
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcScheduledTask_Equals(const PARCScheduledTask *x, const PARCScheduledTask *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (parcFutureTask_Equals(x->task, y->task)) {
+ if (x->executionTime == y->executionTime) {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcScheduledTask_HashCode(const PARCScheduledTask *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+parcScheduledTask_IsValid(const PARCScheduledTask *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcScheduledTask_ToJSON(const PARCScheduledTask *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ if (result != NULL) {
+ }
+
+ return result;
+}
+
+char *
+parcScheduledTask_ToString(const PARCScheduledTask *instance)
+{
+ char *result = parcMemory_Format("PARCScheduledTask@%p\n", instance);
+
+ return result;
+}
+
+uint64_t
+parcScheduledTask_GetExecutionTime(const PARCScheduledTask *task)
+{
+ return task->executionTime;
+}
+
+bool
+parcScheduledTask_Cancel(PARCScheduledTask *task, bool mayInterruptIfRunning)
+{
+ return parcFutureTask_Cancel(task->task, mayInterruptIfRunning);
+}
+
+PARCFutureTaskResult
+parcScheduledTask_Get(const PARCScheduledTask *task, const PARCTimeout *timeout)
+{
+ return parcFutureTask_Get(task->task, timeout);
+}
+
+PARCFutureTask *
+parcScheduledTask_GetTask(const PARCScheduledTask *task)
+{
+ return task->task;
+}
+
+void *
+parcScheduledTask_Run(const PARCScheduledTask *task)
+{
+ return parcFutureTask_Run(task->task);
+}
+
+bool
+parcScheduledTask_IsCancelled(const PARCScheduledTask *task)
+{
+ return parcFutureTask_IsCancelled(task->task);
+}
+
+bool
+parcScheduledTask_IsDone(const PARCScheduledTask *task)
+{
+ return parcFutureTask_IsDone(task->task);
+}
diff --git a/libparc/parc/concurrent/parc_ScheduledTask.h b/libparc/parc/concurrent/parc_ScheduledTask.h
new file mode 100755
index 00000000..e56fb5f5
--- /dev/null
+++ b/libparc/parc/concurrent/parc_ScheduledTask.h
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_ScheduledTask.h
+ * @ingroup threading
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_ScheduledTask
+#define PARCLibrary_parc_ScheduledTask
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/concurrent/parc_FutureTask.h>
+#include <parc/concurrent/parc_Timeout.h>
+
+struct PARCScheduledTask;
+typedef struct PARCScheduledTask PARCScheduledTask;
+
+/**
+ * Increase the number of references to a `PARCScheduledTask` instance.
+ *
+ * Note that new `PARCScheduledTask` is not created,
+ * only that the given `PARCScheduledTask` reference count is incremented.
+ * Discard the reference by invoking `parcScheduledTask_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledTask instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * PARCScheduledTask *b = parcScheduledTask_Acquire();
+ *
+ * parcScheduledTask_Release(&a);
+ * parcScheduledTask_Release(&b);
+ * }
+ * @endcode
+ */
+PARCScheduledTask *parcScheduledTask_Acquire(const PARCScheduledTask *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcScheduledTask_OptionalAssertValid(_instance_)
+#else
+# define parcScheduledTask_OptionalAssertValid(_instance_) parcScheduledTask_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCScheduledTask` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledTask instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * parcScheduledTask_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcScheduledTask_Release(&b);
+ * }
+ * @endcode
+ */
+void parcScheduledTask_AssertValid(const PARCScheduledTask *instance);
+
+/**
+ * Create an instance of PARCScheduledTask
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCScheduledTask instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * parcScheduledTask_Release(&a);
+ * }
+ * @endcode
+ */
+PARCScheduledTask *parcScheduledTask_Create(PARCFutureTask *task, uint64_t executionTime);
+
+/**
+ * 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 PARCScheduledTask instance.
+ * @param [in] other A pointer to a valid PARCScheduledTask 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
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ * PARCScheduledTask *b = parcScheduledTask_Create();
+ *
+ * if (parcScheduledTask_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcScheduledTask_Release(&a);
+ * parcScheduledTask_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcScheduledTask_Equals
+ */
+int parcScheduledTask_Compare(const PARCScheduledTask *instance, const PARCScheduledTask *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 PARCScheduledTask instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCScheduledTask` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * PARCScheduledTask *copy = parcScheduledTask_Copy(&b);
+ *
+ * parcScheduledTask_Release(&b);
+ * parcScheduledTask_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCScheduledTask *parcScheduledTask_Copy(const PARCScheduledTask *original);
+
+/**
+ * Print a human readable representation of the given `PARCScheduledTask`.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledTask instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * parcScheduledTask_Display(a, 0);
+ *
+ * parcScheduledTask_Release(&a);
+ * }
+ * @endcode
+ */
+void parcScheduledTask_Display(const PARCScheduledTask *instance, int indentation);
+
+/**
+ * Determine if two `PARCScheduledTask` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCScheduledTask` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcScheduledTask_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcScheduledTask_Equals(x, y)` must return true if and only if
+ * `parcScheduledTask_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcScheduledTask_Equals(x, y)` returns true and
+ * `parcScheduledTask_Equals(y, z)` returns true,
+ * then `parcScheduledTask_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcScheduledTask_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcScheduledTask_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCScheduledTask instance.
+ * @param [in] y A pointer to a valid PARCScheduledTask instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ * PARCScheduledTask *b = parcScheduledTask_Create();
+ *
+ * if (parcScheduledTask_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcScheduledTask_Release(&a);
+ * parcScheduledTask_Release(&b);
+ * }
+ * @endcode
+ * @see parcScheduledTask_HashCode
+ */
+bool parcScheduledTask_Equals(const PARCScheduledTask *x, const PARCScheduledTask *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 parcScheduledTask_Equals} method,
+ * then calling the {@link parcScheduledTask_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 parcScheduledTask_Equals} function,
+ * then calling the `parcScheduledTask_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledTask instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * PARCHashCode hashValue = parcScheduledTask_HashCode(buffer);
+ * parcScheduledTask_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcScheduledTask_HashCode(const PARCScheduledTask *instance);
+
+/**
+ * Determine if an instance of `PARCScheduledTask` 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 PARCScheduledTask instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * if (parcScheduledTask_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcScheduledTask_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcScheduledTask_IsValid(const PARCScheduledTask *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCScheduledTask` 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
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * parcScheduledTask_Release(&a);
+ * }
+ * @endcode
+ */
+void parcScheduledTask_Release(PARCScheduledTask **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledTask 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
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * PARCJSON *json = parcScheduledTask_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcScheduledTask_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcScheduledTask_ToJSON(const PARCScheduledTask *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCScheduledTask`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledTask 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
+ * {
+ * PARCScheduledTask *a = parcScheduledTask_Create();
+ *
+ * char *string = parcScheduledTask_ToString(a);
+ *
+ * parcScheduledTask_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcScheduledTask_Display
+ */
+char *parcScheduledTask_ToString(const PARCScheduledTask *instance);
+
+/**
+ * Returns the remaining delay associated with this object.
+ *
+ * @param [in] task A pointer to a valid PARCScheduledTask instance.
+ *
+ * @return the remaining delay; zero or negative values indicate that the delay has already elapsed
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+uint64_t parcScheduledTask_GetExecutionTime(const PARCScheduledTask *task);
+
+/**
+ * Attempts to cancel execution of this task.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcScheduledTask_Cancel(PARCScheduledTask *task, bool mayInterruptIfRunning);
+
+/**
+ * Waits if necessary for at most the given time for the computation to complete, and then retrieves its result, if available.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFutureTaskResult parcScheduledTask_Get(const PARCScheduledTask *task, const PARCTimeout *timeout);
+
+
+void *parcScheduledTask_Run(const PARCScheduledTask *task);
+
+
+/**
+ * Get the `PARCFutureTask` instance for the given `PARCScheduledTask`
+ *
+ * @param [in] task A pointer to a valid `PARCScheduledTask` instance.
+ *
+ * @return the `PARCFutureTask` instance for the given `PARCScheduledTask`
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCFutureTask *parcScheduledTask_GetTask(const PARCScheduledTask *task);
+
+/**
+ * Returns true if this task was cancelled before it completed normally.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcScheduledTask_IsCancelled(const PARCScheduledTask *task);
+
+/**
+ * Returns true if this task completed.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcScheduledTask_IsDone(const PARCScheduledTask *task);
+#endif
diff --git a/libparc/parc/concurrent/parc_ScheduledThreadPool.c b/libparc/parc/concurrent/parc_ScheduledThreadPool.c
new file mode 100644
index 00000000..3d6c3e57
--- /dev/null
+++ b/libparc/parc/concurrent/parc_ScheduledThreadPool.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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_SortedList.h>
+#include <parc/algol/parc_LinkedList.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Time.h>
+
+#include <parc/concurrent/parc_ScheduledThreadPool.h>
+#include <parc/concurrent/parc_Thread.h>
+#include <parc/concurrent/parc_ThreadPool.h>
+
+struct PARCScheduledThreadPool {
+ bool continueExistingPeriodicTasksAfterShutdown;
+ bool executeExistingDelayedTasksAfterShutdown;
+ bool removeOnCancel;
+ PARCSortedList *workQueue;
+ PARCThread *workerThread;
+ PARCThreadPool *threadPool;
+ int poolSize;
+};
+
+static void *
+_workerThread(PARCThread *thread, PARCScheduledThreadPool *pool)
+{
+ while (parcThread_IsCancelled(thread) == false) {
+ if (parcSortedList_Lock(pool->workQueue)) {
+ if (parcSortedList_Size(pool->workQueue) > 0) {
+ PARCScheduledTask *task = parcSortedList_GetFirst(pool->workQueue);
+ int64_t executionDelay = parcScheduledTask_GetExecutionTime(task) - parcTime_NowNanoseconds();
+ if (task != NULL && executionDelay <= 0) {
+ parcSortedList_RemoveFirst(pool->workQueue);
+ parcSortedList_Unlock(pool->workQueue);
+ parcThreadPool_Execute(pool->threadPool, parcScheduledTask_GetTask(task));
+ parcScheduledTask_Release(&task);
+ parcSortedList_Lock(pool->workQueue);
+
+ parcSortedList_Notify(pool->workQueue);
+ } else {
+ parcSortedList_WaitFor(pool->workQueue, executionDelay);
+ }
+ } else {
+ parcSortedList_Wait(pool->workQueue);
+ }
+ }
+ parcSortedList_Unlock(pool->workQueue);
+ }
+
+ return NULL;
+}
+
+static bool
+_parcScheduledThreadPool_Destructor(PARCScheduledThreadPool **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCScheduledThreadPool pointer.");
+ PARCScheduledThreadPool *pool = *instancePtr;
+ parcThreadPool_Release(&pool->threadPool);
+
+ parcThread_Release(&pool->workerThread);
+
+ if (parcObject_Lock(pool->workQueue)) {
+ parcSortedList_Release(&pool->workQueue);
+ } else {
+ assertTrue(false, "Cannot lock the work queue.");
+ }
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcScheduledThreadPool, PARCScheduledThreadPool);
+
+parcObject_ImplementRelease(parcScheduledThreadPool, PARCScheduledThreadPool);
+
+parcObject_Override(PARCScheduledThreadPool, PARCObject,
+ .isLockable = true,
+ .destructor = (PARCObjectDestructor *) _parcScheduledThreadPool_Destructor,
+ .copy = (PARCObjectCopy *) parcScheduledThreadPool_Copy,
+ .toString = (PARCObjectToString *) parcScheduledThreadPool_ToString,
+ .equals = (PARCObjectEquals *) parcScheduledThreadPool_Equals,
+ .compare = (PARCObjectCompare *) parcScheduledThreadPool_Compare,
+ .hashCode = (PARCObjectHashCode *) parcScheduledThreadPool_HashCode);
+
+void
+parcScheduledThreadPool_AssertValid(const PARCScheduledThreadPool *instance)
+{
+ assertTrue(parcScheduledThreadPool_IsValid(instance),
+ "PARCScheduledThreadPool is not valid.");
+}
+
+PARCScheduledThreadPool *
+parcScheduledThreadPool_Create(int poolSize)
+{
+ PARCScheduledThreadPool *result = parcObject_CreateInstance(PARCScheduledThreadPool);
+
+ if (result != NULL) {
+ result->poolSize = poolSize;
+ result->workQueue = parcSortedList_Create();
+ result->threadPool = parcThreadPool_Create(poolSize);
+
+ result->continueExistingPeriodicTasksAfterShutdown = false;
+ result->executeExistingDelayedTasksAfterShutdown = false;
+ result->removeOnCancel = true;
+
+ if (parcObject_Lock(result)) {
+ result->workerThread = parcThread_Create((void *(*)(PARCThread *, PARCObject *))_workerThread, (PARCObject *) result);
+ parcThread_Start(result->workerThread);
+ parcObject_Unlock(result);
+ }
+ }
+
+ return result;
+}
+
+int
+parcScheduledThreadPool_Compare(const PARCScheduledThreadPool *instance, const PARCScheduledThreadPool *other)
+{
+ int result = 0;
+
+ return result;
+}
+
+PARCScheduledThreadPool *
+parcScheduledThreadPool_Copy(const PARCScheduledThreadPool *original)
+{
+ PARCScheduledThreadPool *result = parcScheduledThreadPool_Create(original->poolSize);
+
+ return result;
+}
+
+void
+parcScheduledThreadPool_Display(const PARCScheduledThreadPool *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCScheduledThreadPool@%p {", instance);
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcScheduledThreadPool_Equals(const PARCScheduledThreadPool *x, const PARCScheduledThreadPool *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (x->poolSize == y->poolSize) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcScheduledThreadPool_HashCode(const PARCScheduledThreadPool *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+parcScheduledThreadPool_IsValid(const PARCScheduledThreadPool *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcScheduledThreadPool_ToJSON(const PARCScheduledThreadPool *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ if (result != NULL) {
+ }
+
+ return result;
+}
+
+char *
+parcScheduledThreadPool_ToString(const PARCScheduledThreadPool *instance)
+{
+ char *result = parcMemory_Format("PARCScheduledThreadPool@%p\n", instance);
+
+ return result;
+}
+
+void
+parcScheduledThreadPool_Execute(PARCScheduledThreadPool *pool, PARCFutureTask *command)
+{
+}
+
+bool
+parcScheduledThreadPool_GetContinueExistingPeriodicTasksAfterShutdownPolicy(PARCScheduledThreadPool *pool)
+{
+ return pool->continueExistingPeriodicTasksAfterShutdown;
+}
+
+bool
+parcScheduledThreadPool_GetExecuteExistingDelayedTasksAfterShutdownPolicy(PARCScheduledThreadPool *pool)
+{
+ return pool->executeExistingDelayedTasksAfterShutdown;
+}
+
+PARCSortedList *
+parcScheduledThreadPool_GetQueue(const PARCScheduledThreadPool *pool)
+{
+ return pool->workQueue;
+}
+
+bool
+parcScheduledThreadPool_GetRemoveOnCancelPolicy(const PARCScheduledThreadPool *pool)
+{
+ return pool->removeOnCancel;
+}
+
+PARCScheduledTask *
+parcScheduledThreadPool_Schedule(PARCScheduledThreadPool *pool, PARCFutureTask *task, const PARCTimeout *delay)
+{
+ uint64_t executionTime = parcTime_NowNanoseconds() + parcTimeout_InNanoSeconds(delay);
+
+ PARCScheduledTask *scheduledTask = parcScheduledTask_Create(task, executionTime);
+
+ if (parcSortedList_Lock(pool->workQueue)) {
+ parcSortedList_Add(pool->workQueue, scheduledTask);
+ parcScheduledTask_Release(&scheduledTask);
+ parcSortedList_Notify(pool->workQueue);
+ parcSortedList_Unlock(pool->workQueue);
+ }
+ return scheduledTask;
+}
+
+PARCScheduledTask *
+parcScheduledThreadPool_ScheduleAtFixedRate(PARCScheduledThreadPool *pool, PARCFutureTask *task, PARCTimeout initialDelay, PARCTimeout period)
+{
+ return NULL;
+}
+
+PARCScheduledTask *
+parcScheduledThreadPool_ScheduleWithFixedDelay(PARCScheduledThreadPool *pool, PARCFutureTask *task, PARCTimeout initialDelay, PARCTimeout delay)
+{
+ return NULL;
+}
+
+void
+parcScheduledThreadPool_SetContinueExistingPeriodicTasksAfterShutdownPolicy(PARCScheduledThreadPool *pool, bool value)
+{
+}
+
+void
+parcScheduledThreadPool_SetExecuteExistingDelayedTasksAfterShutdownPolicy(PARCScheduledThreadPool *pool, bool value)
+{
+}
+
+void
+parcScheduledThreadPool_SetRemoveOnCancelPolicy(PARCScheduledThreadPool *pool, bool value)
+{
+}
+
+void
+parcScheduledThreadPool_Shutdown(PARCScheduledThreadPool *pool)
+{
+ parcScheduledThreadPool_ShutdownNow(pool);
+}
+
+PARCList *
+parcScheduledThreadPool_ShutdownNow(PARCScheduledThreadPool *pool)
+{
+ parcThread_Cancel(pool->workerThread);
+
+ parcThreadPool_ShutdownNow(pool->threadPool);
+
+ // Wake them all up so they detect that they are cancelled.
+ if (parcObject_Lock(pool)) {
+ parcObject_NotifyAll(pool);
+ parcObject_Unlock(pool);
+ }
+ if (parcObject_Lock(pool->workQueue)) {
+ parcObject_NotifyAll(pool->workQueue);
+ parcObject_Unlock(pool->workQueue);
+ }
+
+ parcThread_Join(pool->workerThread);
+
+ return NULL;
+}
+
+PARCScheduledTask *
+parcScheduledThreadPool_Submit(PARCScheduledThreadPool *pool, PARCFutureTask *task)
+{
+ PARCScheduledTask *scheduledTask = parcScheduledTask_Create(task, 0);
+
+ parcSortedList_Add(pool->workQueue, scheduledTask);
+
+ return scheduledTask;
+}
diff --git a/libparc/parc/concurrent/parc_ScheduledThreadPool.h b/libparc/parc/concurrent/parc_ScheduledThreadPool.h
new file mode 100755
index 00000000..36c26909
--- /dev/null
+++ b/libparc/parc/concurrent/parc_ScheduledThreadPool.h
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_ScheduledThreadPool.h
+ * @ingroup threading
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_ScheduledThreadPool
+#define PARCLibrary_parc_ScheduledThreadPool
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_SortedList.h>
+#include <parc/concurrent/parc_FutureTask.h>
+#include <parc/concurrent/parc_ScheduledTask.h>
+#include <parc/concurrent/parc_Timeout.h>
+
+struct PARCScheduledThreadPool;
+typedef struct PARCScheduledThreadPool PARCScheduledThreadPool;
+
+/**
+ * Increase the number of references to a `PARCScheduledThreadPool` instance.
+ *
+ * Note that new `PARCScheduledThreadPool` is not created,
+ * only that the given `PARCScheduledThreadPool` reference count is incremented.
+ * Discard the reference by invoking `parcScheduledThreadPool_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledThreadPool instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * PARCScheduledThreadPool *b = parcScheduledThreadPool_Acquire();
+ *
+ * parcScheduledThreadPool_Release(&a);
+ * parcScheduledThreadPool_Release(&b);
+ * }
+ * @endcode
+ */
+PARCScheduledThreadPool *parcScheduledThreadPool_Acquire(const PARCScheduledThreadPool *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcScheduledThreadPool_OptionalAssertValid(_instance_)
+#else
+# define parcScheduledThreadPool_OptionalAssertValid(_instance_) parcScheduledThreadPool_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCScheduledThreadPool` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledThreadPool instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * parcScheduledThreadPool_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcScheduledThreadPool_Release(&b);
+ * }
+ * @endcode
+ */
+void parcScheduledThreadPool_AssertValid(const PARCScheduledThreadPool *instance);
+
+/**
+ * Create an instance of PARCScheduledThreadPool
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCScheduledThreadPool instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * parcScheduledThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+PARCScheduledThreadPool *parcScheduledThreadPool_Create(int poolSize);
+
+/**
+ * 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 PARCScheduledThreadPool instance.
+ * @param [in] other A pointer to a valid PARCScheduledThreadPool 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
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ * PARCScheduledThreadPool *b = parcScheduledThreadPool_Create();
+ *
+ * if (parcScheduledThreadPool_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcScheduledThreadPool_Release(&a);
+ * parcScheduledThreadPool_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcScheduledThreadPool_Equals
+ */
+int parcScheduledThreadPool_Compare(const PARCScheduledThreadPool *instance, const PARCScheduledThreadPool *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 PARCScheduledThreadPool instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCScheduledThreadPool` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * PARCScheduledThreadPool *copy = parcScheduledThreadPool_Copy(&b);
+ *
+ * parcScheduledThreadPool_Release(&b);
+ * parcScheduledThreadPool_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCScheduledThreadPool *parcScheduledThreadPool_Copy(const PARCScheduledThreadPool *original);
+
+/**
+ * Print a human readable representation of the given `PARCScheduledThreadPool`.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledThreadPool instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * parcScheduledThreadPool_Display(a, 0);
+ *
+ * parcScheduledThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+void parcScheduledThreadPool_Display(const PARCScheduledThreadPool *instance, int indentation);
+
+/**
+ * Determine if two `PARCScheduledThreadPool` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCScheduledThreadPool` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcScheduledThreadPool_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcScheduledThreadPool_Equals(x, y)` must return true if and only if
+ * `parcScheduledThreadPool_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcScheduledThreadPool_Equals(x, y)` returns true and
+ * `parcScheduledThreadPool_Equals(y, z)` returns true,
+ * then `parcScheduledThreadPool_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcScheduledThreadPool_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcScheduledThreadPool_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCScheduledThreadPool instance.
+ * @param [in] y A pointer to a valid PARCScheduledThreadPool instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ * PARCScheduledThreadPool *b = parcScheduledThreadPool_Create();
+ *
+ * if (parcScheduledThreadPool_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcScheduledThreadPool_Release(&a);
+ * parcScheduledThreadPool_Release(&b);
+ * }
+ * @endcode
+ * @see parcScheduledThreadPool_HashCode
+ */
+bool parcScheduledThreadPool_Equals(const PARCScheduledThreadPool *x, const PARCScheduledThreadPool *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 parcScheduledThreadPool_Equals} method,
+ * then calling the {@link parcScheduledThreadPool_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 parcScheduledThreadPool_Equals} function,
+ * then calling the `parcScheduledThreadPool_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledThreadPool instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * PARCHashCode hashValue = parcScheduledThreadPool_HashCode(buffer);
+ * parcScheduledThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcScheduledThreadPool_HashCode(const PARCScheduledThreadPool *instance);
+
+/**
+ * Determine if an instance of `PARCScheduledThreadPool` 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 PARCScheduledThreadPool instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * if (parcScheduledThreadPool_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcScheduledThreadPool_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcScheduledThreadPool_IsValid(const PARCScheduledThreadPool *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCScheduledThreadPool` 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
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * parcScheduledThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+void parcScheduledThreadPool_Release(PARCScheduledThreadPool **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledThreadPool 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
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * PARCJSON *json = parcScheduledThreadPool_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcScheduledThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcScheduledThreadPool_ToJSON(const PARCScheduledThreadPool *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCScheduledThreadPool`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCScheduledThreadPool 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
+ * {
+ * PARCScheduledThreadPool *a = parcScheduledThreadPool_Create();
+ *
+ * char *string = parcScheduledThreadPool_ToString(a);
+ *
+ * parcScheduledThreadPool_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcScheduledThreadPool_Display
+ */
+char *parcScheduledThreadPool_ToString(const PARCScheduledThreadPool *instance);
+
+/**
+ * Executes command with zero required delay.
+ */
+void parcScheduledThreadPool_Execute(PARCScheduledThreadPool *pool, PARCFutureTask *command);
+
+/**
+ * Gets the policy on whether to continue executing existing periodic tasks even when this executor has been shutdown.
+ */
+bool parcScheduledThreadPool_GetContinueExistingPeriodicTasksAfterShutdownPolicy(PARCScheduledThreadPool *pool);
+
+/**
+ * Gets the policy on whether to execute existing delayed tasks even when this executor has been shutdown.
+ */
+bool parcScheduledThreadPool_GetExecuteExistingDelayedTasksAfterShutdownPolicy(PARCScheduledThreadPool *pool);
+
+/**
+ * Returns the task queue used by this executor.
+ */
+PARCSortedList *parcScheduledThreadPool_GetQueue(const PARCScheduledThreadPool *pool);
+
+/**
+ * Gets the policy on whether cancelled tasks should be immediately removed from the work queue at time of cancellation.
+ */
+bool parcScheduledThreadPool_GetRemoveOnCancelPolicy(const PARCScheduledThreadPool *pool);
+
+/**
+ * Creates and executes a one-shot action that becomes enabled after the given delay.
+ */
+PARCScheduledTask *parcScheduledThreadPool_Schedule(PARCScheduledThreadPool *pool, PARCFutureTask *task, const PARCTimeout *delay);
+
+/**
+ * Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on.
+ */
+PARCScheduledTask *parcScheduledThreadPool_ScheduleAtFixedRate(PARCScheduledThreadPool *pool, PARCFutureTask *task, PARCTimeout initialDelay, PARCTimeout period);
+
+/**
+ * Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given delay between the termination of one execution and the commencement of the next.
+ */
+PARCScheduledTask *parcScheduledThreadPool_ScheduleWithFixedDelay(PARCScheduledThreadPool *pool, PARCFutureTask *task, PARCTimeout initialDelay, PARCTimeout delay);
+
+/**
+ * Sets the policy on whether to continue executing existing periodic tasks even when this executor has been shutdown.
+ */
+void parcScheduledThreadPool_SetContinueExistingPeriodicTasksAfterShutdownPolicy(PARCScheduledThreadPool *pool, bool value);
+
+/**
+ * Sets the policy on whether to execute existing delayed tasks even when this executor has been shutdown.
+ */
+void parcScheduledThreadPool_SetExecuteExistingDelayedTasksAfterShutdownPolicy(PARCScheduledThreadPool *pool, bool value);
+
+/**
+ * Sets the policy on whether cancelled tasks should be immediately removed from the work queue at time of cancellation.
+ */
+void parcScheduledThreadPool_SetRemoveOnCancelPolicy(PARCScheduledThreadPool *pool, bool value);
+
+/**
+ * Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.
+ */
+void parcScheduledThreadPool_Shutdown(PARCScheduledThreadPool *pool);
+
+/**
+ * Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.
+ */
+PARCList *parcScheduledThreadPool_ShutdownNow(PARCScheduledThreadPool *pool);
+
+/**
+ * Submits a PARCFutureTask task for execution and returns the PARCFutureTask representing that task.
+ */
+PARCScheduledTask *parcScheduledThreadPool_Submit(PARCScheduledThreadPool *pool, PARCFutureTask *task);
+#endif
diff --git a/libparc/parc/concurrent/parc_Synchronizer.c b/libparc/parc/concurrent/parc_Synchronizer.c
new file mode 100755
index 00000000..c4475476
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Synchronizer.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/concurrent/parc_Synchronizer.h>
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+# include <pthread.h>
+#else
+//# include <pthread.h>
+#endif
+
+typedef enum {
+ _PARCSynchronizer_Unlocked = 0,
+ _PARCSynchronizer_Locked = 1
+} _PARCSynchronizer;
+
+struct PARCSynchronizer {
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_t mutex;
+#else
+ int mutex;
+#endif
+};
+
+static void
+_parcSynchronizer_Finalize(PARCSynchronizer **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCSynchronizer pointer.");
+
+ parcSynchronizer_OptionalAssertValid((*instancePtr));
+}
+
+parcObject_ImplementAcquire(parcSynchronizer, PARCSynchronizer);
+
+parcObject_ImplementRelease(parcSynchronizer, PARCSynchronizer);
+
+parcObject_ExtendPARCObject(PARCSynchronizer, _parcSynchronizer_Finalize, NULL, NULL, NULL, NULL, NULL, NULL);
+
+void
+parcSynchronizer_AssertValid(const PARCSynchronizer *instance)
+{
+ assertTrue(parcSynchronizer_IsValid(instance),
+ "PARCSynchronizer is not valid.");
+}
+
+PARCSynchronizer *
+parcSynchronizer_Create(void)
+{
+ PARCSynchronizer *result = parcObject_CreateInstance(PARCSynchronizer);
+
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_init(&result->mutex, NULL);
+#else
+ result->mutex = _PARCSynchronizer_Unlocked;
+#endif
+
+ return result;
+}
+
+void
+parcSynchronizer_Display(const PARCSynchronizer *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCSynchronizer@%p {", instance);
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcSynchronizer_IsValid(const PARCSynchronizer *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+bool
+parcSynchronizer_TryLock(PARCSynchronizer *instance)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ bool result = pthread_mutex_trylock(&instance->mutex) == 0;
+#else
+ bool result = __sync_bool_compare_and_swap(&instance->mutex, _PARCSynchronizer_Unlocked, _PARCSynchronizer_Locked);
+#endif
+ return result;
+}
+
+void
+parcSynchronizer_Lock(PARCSynchronizer *instance)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_lock(&instance->mutex);
+#else
+ while (!__sync_bool_compare_and_swap(&instance->mutex, _PARCSynchronizer_Unlocked, _PARCSynchronizer_Locked)) {
+ ;
+ }
+#endif
+}
+
+void
+parcSynchronizer_Unlock(PARCSynchronizer *instance)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ pthread_mutex_unlock(&instance->mutex);
+#else
+ while (!__sync_bool_compare_and_swap(&instance->mutex, _PARCSynchronizer_Locked, _PARCSynchronizer_Unlocked)) {
+ ;
+ }
+#endif
+}
+
+bool
+parcSynchronizer_IsLocked(const PARCSynchronizer *barrier)
+{
+#ifdef PARCLibrary_DISABLE_ATOMICS
+ PARCSynchronizer *instance = (PARCSynchronizer *) barrier;
+
+ bool result = pthread_mutex_trylock(&instance->mutex) != 0;
+ pthread_mutex_unlock(&instance->mutex);
+ return result;
+#else
+ return barrier->mutex == _PARCSynchronizer_Locked;
+#endif
+}
diff --git a/libparc/parc/concurrent/parc_Synchronizer.h b/libparc/parc/concurrent/parc_Synchronizer.h
new file mode 100755
index 00000000..a387888f
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Synchronizer.h
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Synchronizer.h
+ * @ingroup threading
+ * @brief A simple mutual exclusive synchronization implementation.
+ *
+ * Detailed Description
+ *
+ */
+#ifndef PARCLibrary_parc_Barrier
+#define PARCLibrary_parc_Barrier
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+
+struct PARCSynchronizer;
+typedef struct PARCSynchronizer PARCSynchronizer;
+
+/**
+ * Increase the number of references to a `PARCSynchronizer` instance.
+ *
+ * Note that new `PARCSynchronizer` is not created,
+ * only that the given `PARCSynchronizer` reference count is incremented.
+ * Discard the reference by invoking `parcSynchronizer_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCSynchronizer instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSynchronizer *a = parcSynchronizer_Create();
+ *
+ * PARCSynchronizer *b = parcSynchronizer_Acquire();
+ *
+ * parcSynchronizer_Release(&a);
+ * parcSynchronizer_Release(&b);
+ * }
+ * @endcode
+ */
+PARCSynchronizer *parcSynchronizer_Acquire(const PARCSynchronizer *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcSynchronizer_OptionalAssertValid(_instance_)
+#else
+# define parcSynchronizer_OptionalAssertValid(_instance_) parcSynchronizer_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCSynchronizer` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCSynchronizer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSynchronizer *a = parcSynchronizer_Create();
+ *
+ * parcSynchronizer_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcSynchronizer_Release(&b);
+ * }
+ * @endcode
+ */
+void parcSynchronizer_AssertValid(const PARCSynchronizer *instance);
+
+/**
+ * Create an instance of PARCSynchronizer
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCSynchronizer instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSynchronizer *a = parcSynchronizer_Create();
+ *
+ * parcSynchronizer_Release(&a);
+ * }
+ * @endcode
+ */
+PARCSynchronizer *parcSynchronizer_Create(void);
+
+/**
+ * Print a human readable representation of the given `PARCSynchronizer`.
+ *
+ * @param [in] instance A pointer to a valid PARCSynchronizer instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSynchronizer *a = parcSynchronizer_Create();
+ *
+ * parcSynchronizer_Display(a, 0);
+ *
+ * parcSynchronizer_Release(&a);
+ * }
+ * @endcode
+ */
+void parcSynchronizer_Display(const PARCSynchronizer *instance, int indentation);
+
+/**
+ * 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 parcSynchronizer_Equals} method,
+ * then calling the {@link parcSynchronizer_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 parcSynchronizer_Equals} function,
+ * then calling the `parcSynchronizer_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCSynchronizer instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSynchronizer *a = parcSynchronizer_Create();
+ *
+ * uint32_t hashValue = parcSynchronizer_HashCode(buffer);
+ * parcSynchronizer_Release(&a);
+ * }
+ * @endcode
+ */
+int parcSynchronizer_HashCode(const PARCSynchronizer *instance);
+
+/**
+ * Determine if an instance of `PARCSynchronizer` 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 PARCSynchronizer instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSynchronizer *a = parcSynchronizer_Create();
+ *
+ * if (parcSynchronizer_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcSynchronizer_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcSynchronizer_IsValid(const PARCSynchronizer *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCSynchronizer` 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
+ * {
+ * PARCSynchronizer *a = parcSynchronizer_Create();
+ *
+ * parcSynchronizer_Release(&a);
+ * }
+ * @endcode
+ */
+void parcSynchronizer_Release(PARCSynchronizer **instancePtr);
+
+/**
+ * Attempt to lock the given PARCSynchronizer.
+ *
+ * If the synchronizer is already locked, this function returns `false`.
+ * Otherwise, the lock is established and this function returns `true`.
+ *
+ * @param [in] barrier A pointer to a valid PARCSynchronizer instance.
+ *
+ * @return `true` The PARCSynchronizer was successfully set.
+ * @return `false` The PARCSynchronizer could not be set.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcSynchronizer_TryLock(PARCSynchronizer *barrier);
+
+/**
+ * Lock the given PARCSynchronizer.
+ *
+ * If the synchronizer is already locked, this function blocks the caller until it is able to acquire the lock.
+ *
+ * @param [in] barrier A pointer to a valid PARCSynchronizer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcSynchronizer_Lock(PARCSynchronizer *barrier);
+
+/**
+ * Unlock the given PARCSynchronizer.
+ *
+ * @param [in] barrier A pointer to a valid PARCSynchronizer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcSynchronizer_Unlock(PARCSynchronizer *barrier);
+
+/**
+ * Check if a PARCSynchronizer is locked.
+ *
+ * @param [in] synchronizer A pointer to a valid PARCSynchronizer instance.
+ *
+ * @return true The specified synchronizer is currently locked.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSynchronizer *a = parcSynchronizer_Create();
+ *
+ * if (parcSynchronizer_IsLocked(a) == true) {
+ * printf("A PARCSynchronizer cannot be created in the locked state.\n");
+ * }
+ *
+ * parcSynchronizer_Release(&a);
+ * }
+ * @endcode
+ */
+bool parcSynchronizer_IsLocked(const PARCSynchronizer *synchronizer);
+#endif
diff --git a/libparc/parc/concurrent/parc_Thread.c b/libparc/parc/concurrent/parc_Thread.c
new file mode 100644
index 00000000..4bccc47f
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Thread.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+#include <pthread.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/concurrent/parc_Thread.h>
+
+struct PARCThread {
+ void *(*run)(PARCThread *, PARCObject *param);
+ PARCObject *argument;
+ bool isCancelled;
+ bool isRunning;
+ pthread_t thread;
+};
+
+static bool
+_parcThread_Destructor(PARCThread **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCThread pointer.");
+ PARCThread *thread = *instancePtr;
+
+ if (thread->argument != NULL) {
+ parcObject_Release(&thread->argument);
+ }
+
+ thread->isCancelled = true;
+ parcThread_Join(thread);
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcThread, PARCThread);
+
+parcObject_ImplementRelease(parcThread, PARCThread);
+
+parcObject_Override(PARCThread, PARCObject,
+ .isLockable = true,
+ .destructor = (PARCObjectDestructor *) _parcThread_Destructor,
+ .copy = (PARCObjectCopy *) parcThread_Copy,
+ .toString = (PARCObjectToString *) parcThread_ToString,
+ .equals = (PARCObjectEquals *) parcThread_Equals,
+ .compare = (PARCObjectCompare *) parcThread_Compare,
+ .hashCode = (PARCObjectHashCode *) parcThread_HashCode,
+ .display = (PARCObjectDisplay *) parcThread_Display
+ );
+
+void
+parcThread_AssertValid(const PARCThread *instance)
+{
+ assertTrue(parcThread_IsValid(instance),
+ "PARCThread is not valid.");
+}
+
+PARCThread *
+parcThread_Create(void *(*runFunction)(PARCThread *, PARCObject *), PARCObject *restrict parameter)
+{
+ assertNotNull(parameter, "Parameter cannot be NULL.");
+
+ PARCThread *result = parcObject_CreateAndClearInstance(PARCThread);
+
+ if (result) {
+ result->run = runFunction;
+ result->argument = parcObject_Acquire(parameter);
+ result->isCancelled = false;
+ result->isRunning = false;
+ }
+
+ return result;
+}
+
+int
+parcThread_Compare(const PARCThread *instance, const PARCThread *other)
+{
+ int result = 0;
+ return result;
+}
+
+PARCThread *
+parcThread_Copy(const PARCThread *original)
+{
+ PARCThread *result = parcThread_Create(original->run, original->argument);
+ result->isCancelled = original->isCancelled;
+ result->isRunning = original->isRunning;
+
+ return result;
+}
+
+void
+parcThread_Display(const PARCThread *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCThread@%p {", instance);
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcThread_Equals(const PARCThread *x, const PARCThread *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ result = pthread_equal(x->thread, y->thread);
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcThread_HashCode(const PARCThread *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+parcThread_IsValid(const PARCThread *thread)
+{
+ bool result = false;
+
+ if (thread != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcThread_ToJSON(const PARCThread *thread)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ return result;
+}
+
+char *
+parcThread_ToString(const PARCThread *thread)
+{
+ char *result = parcMemory_Format("PARCThread@%p{.id=%p, .isCancelled=%s}", thread, thread->thread, thread->isCancelled ? "true" : "false");
+
+ return result;
+}
+
+static void *
+_parcThread_Run(PARCThread *thread)
+{
+ thread->isRunning = true;
+ thread->run(thread, thread->argument);
+ thread->isRunning = false;
+
+ // The thread is done, release the reference to the argument acquired when this PARCThread was created.
+ // This prevents the reference from lingering leading to memory leaks if the thread is not properly joined.
+ if (thread->argument != NULL) {
+ parcObject_Release(&thread->argument);
+ }
+ // Release the thread reference that was acquired *before* this thread was started.
+ parcThread_Release(&thread);
+
+ return NULL;
+}
+
+void
+parcThread_Start(PARCThread *thread)
+{
+ PARCThread *parameter = parcThread_Acquire(thread);
+ pthread_create(&thread->thread, NULL, (void *(*)(void *))_parcThread_Run, parameter);
+}
+
+PARCObject *
+parcThread_GetParameter(const PARCThread *thread)
+{
+ return thread->argument;
+}
+
+bool
+parcThread_Cancel(PARCThread *thread)
+{
+ if (parcThread_Lock(thread)) {
+ thread->isCancelled = true;
+ parcThread_Notify(thread);
+ parcThread_Unlock(thread);
+ }
+ return true;
+}
+
+int
+parcThread_GetId(const PARCThread *thread)
+{
+ return (int) thread->thread;
+}
+
+bool
+parcThread_IsRunning(const PARCThread *thread)
+{
+ return thread->isRunning;
+}
+
+bool
+parcThread_IsCancelled(const PARCThread *thread)
+{
+ return thread->isCancelled;
+}
+
+void
+parcThread_Join(PARCThread *thread)
+{
+ pthread_join(thread->thread, NULL);
+}
diff --git a/libparc/parc/concurrent/parc_Thread.h b/libparc/parc/concurrent/parc_Thread.h
new file mode 100755
index 00000000..f24306ae
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Thread.h
@@ -0,0 +1,601 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Thread.h
+ * @ingroup threading
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_Thread
+#define PARCLibrary_parc_Thread
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+struct PARCThread;
+typedef struct PARCThread PARCThread;
+
+/**
+ * Increase the number of references to a `PARCThread` instance.
+ *
+ * Note that new `PARCThread` is not created,
+ * only that the given `PARCThread` reference count is incremented.
+ * Discard the reference by invoking `parcThread_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCThread instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * PARCThread *b = parcThread_Acquire();
+ *
+ * parcThread_Release(&a);
+ * parcThread_Release(&b);
+ * }
+ * @endcode
+ */
+PARCThread *parcThread_Acquire(const PARCThread *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcThread_OptionalAssertValid(_instance_)
+#else
+# define parcThread_OptionalAssertValid(_instance_) parcThread_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCThread` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCThread instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * parcThread_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcThread_Release(&b);
+ * }
+ * @endcode
+ */
+void parcThread_AssertValid(const PARCThread *instance);
+
+/**
+ * Create an instance of PARCThread
+ *
+ * @return non-NULL A pointer to a valid PARCThread instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * MyTask *task = myTask_Create();
+ * PARCThread *thread = parcThread_Create(myTask_Run, myTask);
+ *
+ * parcThread_Start(a);
+ *
+ * parcThread_Release(&a);
+ * }
+ * @endcode
+ */
+//#define parcThread_Create(_runFunction_, _argument_) parcThread_CreateImpl((void (*)(PARCObject *)) _runFunction_, (PARCObject *) _argument_)
+
+PARCThread *parcThread_Create(void *(*run)(PARCThread *, PARCObject *), PARCObject *restrict argument);
+
+/**
+ * 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 PARCThread instance.
+ * @param [in] other A pointer to a valid PARCThread 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
+ * {
+ * PARCThread *a = parcThread_Create();
+ * PARCThread *b = parcThread_Create();
+ *
+ * if (parcThread_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcThread_Release(&a);
+ * parcThread_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcThread_Equals
+ */
+int parcThread_Compare(const PARCThread *instance, const PARCThread *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 PARCThread instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCThread` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * PARCThread *copy = parcThread_Copy(&b);
+ *
+ * parcThread_Release(&b);
+ * parcThread_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCThread *parcThread_Copy(const PARCThread *original);
+
+/**
+ * Print a human readable representation of the given `PARCThread`.
+ *
+ * @param [in] instance A pointer to a valid PARCThread instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * parcThread_Display(a, 0);
+ *
+ * parcThread_Release(&a);
+ * }
+ * @endcode
+ */
+void parcThread_Display(const PARCThread *instance, int indentation);
+
+/**
+ * Determine if two `PARCThread` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCThread` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcThread_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcThread_Equals(x, y)` must return true if and only if
+ * `parcThread_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcThread_Equals(x, y)` returns true and
+ * `parcThread_Equals(y, z)` returns true,
+ * then `parcThread_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcThread_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcThread_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCThread instance.
+ * @param [in] y A pointer to a valid PARCThread instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ * PARCThread *b = parcThread_Create();
+ *
+ * if (parcThread_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcThread_Release(&a);
+ * parcThread_Release(&b);
+ * }
+ * @endcode
+ * @see parcThread_HashCode
+ */
+bool parcThread_Equals(const PARCThread *x, const PARCThread *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 parcThread_Equals} method,
+ * then calling the {@link parcThread_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 parcThread_Equals} function,
+ * then calling the `parcThread_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCThread instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * PARCHashCode hashValue = parcThread_HashCode(buffer);
+ * parcThread_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcThread_HashCode(const PARCThread *instance);
+
+/**
+ * Determine if an instance of `PARCThread` 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 PARCThread instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * if (parcThread_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcThread_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcThread_IsValid(const PARCThread *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCThread` 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
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * parcThread_Release(&a);
+ * }
+ * @endcode
+ */
+void parcThread_Release(PARCThread **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCThread 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
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * PARCJSON *json = parcThread_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcThread_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcThread_ToJSON(const PARCThread *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCThread`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCThread 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
+ * {
+ * PARCThread *a = parcThread_Create();
+ *
+ * char *string = parcThread_ToString(a);
+ *
+ * parcThread_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcThread_Display
+ */
+char *parcThread_ToString(const PARCThread *instance);
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcLinkedList_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] object A pointer to a valid PARCThread instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcThread_Notify(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotify(parcThread, PARCThread);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the parcHashMap_Notify() function on the same object.
+ * *
+ * @param [in] object A pointer to a valid `PARCThread` instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcThread_Wait(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementWait(parcThread, PARCThread);
+
+/**
+ * Obtain the lock on the given `PARCThread` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] object A pointer to a valid `PARCThread` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, or the `PARCThread` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcThread_Lock(object)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementLock(parcThread, PARCThread);
+
+/**
+ * Try to obtain the advisory lock on the given PARCThread instance.
+ *
+ * Once the lock is obtained, the caller must release the lock as soon as possible.
+ *
+ * @param [in] object A pointer to a valid PARCThread instance.
+ *
+ * @return true The PARCThread is locked.
+ * @return false The PARCThread is unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcThread_TryLock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementTryLock(parcThread, PARCThread);
+
+/**
+ * Try to unlock the advisory lock on the given `PARCHashMap` instance.
+ *
+ * @param [in] object A pointer to a valid `PARCThread` instance.
+ *
+ * @return true The `PARCThread` was locked and now is unlocked.
+ * @return false The `PARCThread` was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcThread_Unlock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementUnlock(parcThread, PARCThread);
+
+/**
+ * Determine if the advisory lock on the given `PARCThread` instance is locked.
+ *
+ * @param [in] object A pointer to a valid `PARCThread` instance.
+ *
+ * @return true The `PARCThread` is locked.
+ * @return false The `PARCThread` is unlocked.
+ * Example:
+ * @code
+ * {
+ * if (parcThread_IsLocked(object)) {
+ * ...
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementIsLocked(parcThread, PARCThread);
+
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcThread_Start(PARCThread *thread);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCObject *parcThread_GetParameter(const PARCThread *thread);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcThread_Cancel(PARCThread *thread);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcThread_IsCancelled(const PARCThread *thread);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+bool parcThread_IsRunning(const PARCThread *thread);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+int parcThread_GetId(const PARCThread *thread);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in#> | <#out#> | <#in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcThread_Join(PARCThread *thread);
+#endif
diff --git a/libparc/parc/concurrent/parc_ThreadPool.c b/libparc/parc/concurrent/parc_ThreadPool.c
new file mode 100644
index 00000000..80b093ba
--- /dev/null
+++ b/libparc/parc/concurrent/parc_ThreadPool.c
@@ -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.
+ */
+
+/**
+ */
+#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_SortedList.h>
+#include <parc/algol/parc_LinkedList.h>
+
+#include <parc/concurrent/parc_AtomicUint64.h>
+#include <parc/concurrent/parc_ThreadPool.h>
+#include <parc/concurrent/parc_Thread.h>
+
+struct PARCThreadPool {
+ bool continueExistingPeriodicTasksAfterShutdown;
+ bool executeExistingDelayedTasksAfterShutdown;
+ bool removeOnCancel;
+ PARCLinkedList *workQueue;
+ PARCLinkedList *threads;
+ int poolSize;
+ int maximumPoolSize;
+ long taskCount;
+ bool isShutdown;
+ bool isTerminated;
+ bool isTerminating;
+
+ PARCAtomicUint64 *completedTaskCount;
+};
+
+static void *
+_parcThreadPool_Worker(const PARCThread *thread, const PARCThreadPool *pool)
+{
+ while (parcThread_IsCancelled(thread) == false && pool->isTerminated == false) {
+ if (parcLinkedList_Lock(pool->workQueue)) {
+ PARCFutureTask *task = parcLinkedList_RemoveFirst(pool->workQueue);
+ if (task != NULL) {
+ parcAtomicUint64_Increment(pool->completedTaskCount);
+ parcLinkedList_Unlock(pool->workQueue);
+ parcFutureTask_Run(task);
+ parcFutureTask_Release(&task);
+ parcLinkedList_Lock(pool->workQueue);
+
+ parcLinkedList_Notify(pool->workQueue);
+ } else {
+ parcLinkedList_WaitFor(pool->workQueue, 1000000000);
+ }
+ parcLinkedList_Unlock(pool->workQueue);
+ }
+ }
+
+ return NULL;
+}
+
+static void
+_parcThreadPool_CancelAll(const PARCThreadPool *pool)
+{
+ PARCIterator *iterator = parcLinkedList_CreateIterator(pool->threads);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCThread *thread = parcIterator_Next(iterator);
+ parcThread_Cancel(thread);
+ }
+ parcIterator_Release(&iterator);
+}
+
+static void
+_parcThreadPool_JoinAll(const PARCThreadPool *pool)
+{
+ PARCIterator *iterator = parcLinkedList_CreateIterator(pool->threads);
+
+ while (parcIterator_HasNext(iterator)) {
+ PARCThread *thread = parcIterator_Next(iterator);
+ parcThread_Join(thread);
+ }
+ parcIterator_Release(&iterator);
+}
+
+static bool
+_parcThreadPool_Destructor(PARCThreadPool **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCThreadPool pointer.");
+ PARCThreadPool *pool = *instancePtr;
+
+ if (pool->isShutdown == false) {
+ _parcThreadPool_CancelAll(pool);
+ _parcThreadPool_JoinAll(pool);
+ }
+
+ parcAtomicUint64_Release(&pool->completedTaskCount);
+ parcLinkedList_Release(&pool->threads);
+
+ if (parcObject_Lock(pool->workQueue)) {
+ parcLinkedList_Release(&pool->workQueue);
+ }
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcThreadPool, PARCThreadPool);
+
+parcObject_ImplementRelease(parcThreadPool, PARCThreadPool);
+
+parcObject_Override(PARCThreadPool, PARCObject,
+ .isLockable = true,
+ .destructor = (PARCObjectDestructor *) _parcThreadPool_Destructor,
+ .copy = (PARCObjectCopy *) parcThreadPool_Copy,
+ .toString = (PARCObjectToString *) parcThreadPool_ToString,
+ .equals = (PARCObjectEquals *) parcThreadPool_Equals,
+ .compare = (PARCObjectCompare *) parcThreadPool_Compare,
+ .hashCode = (PARCObjectHashCode *) parcThreadPool_HashCode);
+
+void
+parcThreadPool_AssertValid(const PARCThreadPool *instance)
+{
+ assertTrue(parcThreadPool_IsValid(instance),
+ "PARCThreadPool is not valid.");
+}
+
+
+PARCThreadPool *
+parcThreadPool_Create(int poolSize)
+{
+ PARCThreadPool *result = parcObject_CreateInstance(PARCThreadPool);
+
+ if (result != NULL) {
+ result->poolSize = poolSize;
+ result->maximumPoolSize = poolSize;
+ result->taskCount = 0;
+ result->isShutdown = false;
+ result->isTerminated = false;
+ result->isTerminating = false;
+ result->workQueue = parcLinkedList_Create();
+ result->threads = parcLinkedList_Create();
+
+ result->completedTaskCount = parcAtomicUint64_Create(0);
+
+ result->continueExistingPeriodicTasksAfterShutdown = false;
+ result->executeExistingDelayedTasksAfterShutdown = false;
+ result->removeOnCancel = true;
+
+ if (parcObject_Lock(result)) {
+ for (int i = 0; i < poolSize; i++) {
+ PARCThread *thread = parcThread_Create((void *(*)(PARCThread *, PARCObject *))_parcThreadPool_Worker, (PARCObject *) result);
+ parcLinkedList_Append(result->threads, thread);
+ parcThread_Start(thread);
+ parcThread_Release(&thread);
+ }
+ parcObject_Unlock(result);
+ }
+ }
+
+ return result;
+}
+
+int
+parcThreadPool_Compare(const PARCThreadPool *instance, const PARCThreadPool *other)
+{
+ int result = 0;
+
+ return result;
+}
+
+PARCThreadPool *
+parcThreadPool_Copy(const PARCThreadPool *original)
+{
+ PARCThreadPool *result = parcThreadPool_Create(original->poolSize);
+
+ return result;
+}
+
+void
+parcThreadPool_Display(const PARCThreadPool *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCThreadPool@%p {", instance);
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcThreadPool_Equals(const PARCThreadPool *x, const PARCThreadPool *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ /* perform instance specific equality tests here. */
+ if (x->poolSize == y->poolSize) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcThreadPool_HashCode(const PARCThreadPool *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+parcThreadPool_IsValid(const PARCThreadPool *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcThreadPool_ToJSON(const PARCThreadPool *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ if (result != NULL) {
+ }
+
+ return result;
+}
+
+char *
+parcThreadPool_ToString(const PARCThreadPool *instance)
+{
+ char *result = parcMemory_Format("PARCThreadPool@%p\n", instance);
+
+ return result;
+}
+
+void
+parcThreadPool_SetAllowCoreThreadTimeOut(PARCThreadPool *pool, bool value)
+{
+}
+
+bool
+parcThreadPool_GetAllowsCoreThreadTimeOut(const PARCThreadPool *pool)
+{
+ return false;
+}
+
+bool
+parcThreadPool_AwaitTermination(PARCThreadPool *pool, PARCTimeout *timeout)
+{
+ bool result = false;
+
+ if (pool->isTerminating) {
+ if (parcLinkedList_Lock(pool->workQueue)) {
+ while (parcLinkedList_Size(pool->workQueue) > 0) {
+ if (parcTimeout_IsNever(timeout)) {
+ parcLinkedList_Wait(pool->workQueue);
+ } else {
+ // This is not accurate as this will continue the delay, rather than keep a cumulative amount of delay.
+ uint64_t delay = parcTimeout_InNanoSeconds(timeout);
+ parcLinkedList_WaitFor(pool->workQueue, delay);
+ }
+ }
+ result = true;
+ parcLinkedList_Unlock(pool->workQueue);
+ }
+
+ parcThreadPool_ShutdownNow(pool);
+ }
+
+ return result;
+}
+
+bool
+parcThreadPool_Execute(PARCThreadPool *pool, PARCFutureTask *task)
+{
+ bool result = false;
+
+ if (parcThreadPool_Lock(pool)) {
+ if (pool->isShutdown == false) {
+ parcThreadPool_Unlock(pool);
+ if (parcLinkedList_Lock(pool->workQueue)) {
+ parcLinkedList_Append(pool->workQueue, task);
+ parcLinkedList_Notify(pool->workQueue);
+ parcLinkedList_Unlock(pool->workQueue);
+ result = true;
+ }
+ } else {
+ parcThreadPool_Unlock(pool);
+ }
+ }
+
+ return result;
+}
+
+int
+parcThreadPool_GetActiveCount(const PARCThreadPool *pool)
+{
+ return pool->poolSize;
+}
+
+uint64_t
+parcThreadPool_GetCompletedTaskCount(const PARCThreadPool *pool)
+{
+ return parcAtomicUint64_GetValue(pool->completedTaskCount);
+}
+
+int
+parcThreadPool_GetCorePoolSize(const PARCThreadPool *pool)
+{
+ return pool->poolSize;
+}
+
+PARCTimeout *
+parcThreadPool_GetKeepAliveTime(const PARCThreadPool *pool)
+{
+ return PARCTimeout_Never;
+}
+
+int
+parcThreadPool_GetLargestPoolSize(const PARCThreadPool *pool)
+{
+ return pool->poolSize;
+}
+
+int
+parcThreadPool_GetMaximumPoolSize(const PARCThreadPool *pool)
+{
+ return pool->maximumPoolSize;
+}
+
+int
+parcThreadPool_GetPoolSize(const PARCThreadPool *pool)
+{
+ return pool->poolSize;
+}
+
+PARCLinkedList *
+parcThreadPool_GetQueue(const PARCThreadPool *pool)
+{
+ return pool->workQueue;
+}
+
+long
+parcThreadPool_GetTaskCount(const PARCThreadPool *pool)
+{
+ return pool->taskCount;
+}
+
+bool
+parcThreadPool_IsShutdown(const PARCThreadPool *pool)
+{
+ return pool->isShutdown;
+}
+
+bool
+parcThreadPool_IsTerminated(const PARCThreadPool *pool)
+{
+ return pool->isTerminated;
+}
+
+bool
+parcThreadPool_IsTerminating(const PARCThreadPool *pool)
+{
+ return pool->isTerminating;
+}
+
+int
+parcThreadPool_PrestartAllCoreThreads(PARCThreadPool *pool)
+{
+ return 0;
+}
+
+bool
+parcThreadPool_PrestartCoreThread(PARCThreadPool *pool)
+{
+ return 0;
+}
+
+void
+parcThreadPool_Purge(PARCThreadPool *pool)
+{
+}
+
+bool
+parcThreadPool_Remove(PARCThreadPool *pool, PARCFutureTask *task)
+{
+ return false;
+}
+
+void
+parcThreadPool_SetCorePoolSize(PARCThreadPool *pool, int corePoolSize)
+{
+}
+
+void
+parcThreadPool_SetKeepAliveTime(PARCThreadPool *pool, PARCTimeout *timeout)
+{
+}
+
+void
+parcThreadPool_SetMaximumPoolSize(PARCThreadPool *pool, int maximumPoolSize)
+{
+}
+
+void
+parcThreadPool_Shutdown(PARCThreadPool *pool)
+{
+ if (parcThreadPool_Lock(pool)) {
+ pool->isShutdown = true;
+ pool->isTerminating = true;
+ parcThreadPool_Unlock(pool);
+ }
+}
+
+PARCLinkedList *
+parcThreadPool_ShutdownNow(PARCThreadPool *pool)
+{
+ parcThreadPool_Shutdown(pool);
+
+ // Cause all of the worker threads to exit.
+ _parcThreadPool_CancelAll(pool);
+
+ // Wake them all up so they detect that they are cancelled.
+ if (parcThreadPool_Lock(pool)) {
+ parcThreadPool_NotifyAll(pool);
+ parcThreadPool_Unlock(pool);
+ }
+
+ if (parcLinkedList_Lock(pool->workQueue)) {
+ parcLinkedList_NotifyAll(pool->workQueue);
+ parcLinkedList_Unlock(pool->workQueue);
+ }
+ // Join with all of them, thereby cleaning up all of them.
+ _parcThreadPool_JoinAll(pool);
+
+ pool->isTerminated = true;
+ return NULL;
+}
diff --git a/libparc/parc/concurrent/parc_ThreadPool.h b/libparc/parc/concurrent/parc_ThreadPool.h
new file mode 100755
index 00000000..7a7b548e
--- /dev/null
+++ b/libparc/parc/concurrent/parc_ThreadPool.h
@@ -0,0 +1,625 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_ThreadPool.h
+ * @ingroup threading
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef PARCLibrary_parc_ThreadPool
+#define PARCLibrary_parc_ThreadPool
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_LinkedList.h>
+#include <parc/concurrent/parc_Timeout.h>
+#include <parc/concurrent/parc_FutureTask.h>
+
+struct PARCThreadPool;
+typedef struct PARCThreadPool PARCThreadPool;
+
+/**
+ * Increase the number of references to a `PARCThreadPool` instance.
+ *
+ * Note that new `PARCThreadPool` is not created,
+ * only that the given `PARCThreadPool` reference count is incremented.
+ * Discard the reference by invoking `parcThreadPool_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCThreadPool instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * PARCThreadPool *b = parcThreadPool_Acquire();
+ *
+ * parcThreadPool_Release(&a);
+ * parcThreadPool_Release(&b);
+ * }
+ * @endcode
+ */
+PARCThreadPool *parcThreadPool_Acquire(const PARCThreadPool *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcThreadPool_OptionalAssertValid(_instance_)
+#else
+# define parcThreadPool_OptionalAssertValid(_instance_) parcThreadPool_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCThreadPool` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCThreadPool instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * parcThreadPool_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcThreadPool_Release(&b);
+ * }
+ * @endcode
+ */
+void parcThreadPool_AssertValid(const PARCThreadPool *instance);
+
+/**
+ * Create an instance of PARCThreadPool
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCThreadPool instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * parcThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+PARCThreadPool *parcThreadPool_Create(int poolSize);
+
+/**
+ * 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 PARCThreadPool instance.
+ * @param [in] other A pointer to a valid PARCThreadPool 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
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ * PARCThreadPool *b = parcThreadPool_Create();
+ *
+ * if (parcThreadPool_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcThreadPool_Release(&a);
+ * parcThreadPool_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcThreadPool_Equals
+ */
+int parcThreadPool_Compare(const PARCThreadPool *instance, const PARCThreadPool *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 PARCThreadPool instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCThreadPool` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * PARCThreadPool *copy = parcThreadPool_Copy(&b);
+ *
+ * parcThreadPool_Release(&b);
+ * parcThreadPool_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCThreadPool *parcThreadPool_Copy(const PARCThreadPool *original);
+
+/**
+ * Print a human readable representation of the given `PARCThreadPool`.
+ *
+ * @param [in] instance A pointer to a valid PARCThreadPool instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * parcThreadPool_Display(a, 0);
+ *
+ * parcThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+void parcThreadPool_Display(const PARCThreadPool *instance, int indentation);
+
+/**
+ * Determine if two `PARCThreadPool` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCThreadPool` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcThreadPool_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcThreadPool_Equals(x, y)` must return true if and only if
+ * `parcThreadPool_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcThreadPool_Equals(x, y)` returns true and
+ * `parcThreadPool_Equals(y, z)` returns true,
+ * then `parcThreadPool_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcThreadPool_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcThreadPool_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCThreadPool instance.
+ * @param [in] y A pointer to a valid PARCThreadPool instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ * PARCThreadPool *b = parcThreadPool_Create();
+ *
+ * if (parcThreadPool_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcThreadPool_Release(&a);
+ * parcThreadPool_Release(&b);
+ * }
+ * @endcode
+ * @see parcThreadPool_HashCode
+ */
+bool parcThreadPool_Equals(const PARCThreadPool *x, const PARCThreadPool *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 parcThreadPool_Equals} method,
+ * then calling the {@link parcThreadPool_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 parcThreadPool_Equals} function,
+ * then calling the `parcThreadPool_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCThreadPool instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * PARCHashCode hashValue = parcThreadPool_HashCode(buffer);
+ * parcThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcThreadPool_HashCode(const PARCThreadPool *instance);
+
+/**
+ * Determine if an instance of `PARCThreadPool` 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 PARCThreadPool instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * if (parcThreadPool_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcThreadPool_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcThreadPool_IsValid(const PARCThreadPool *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCThreadPool` 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
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * parcThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+void parcThreadPool_Release(PARCThreadPool **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCThreadPool 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
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * PARCJSON *json = parcThreadPool_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcThreadPool_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcThreadPool_ToJSON(const PARCThreadPool *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCThreadPool`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCThreadPool 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
+ * {
+ * PARCThreadPool *a = parcThreadPool_Create();
+ *
+ * char *string = parcThreadPool_ToString(a);
+ *
+ * parcThreadPool_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcThreadPool_Display
+ */
+char *parcThreadPool_ToString(const PARCThreadPool *instance);
+
+/**
+ * Wakes up a single thread that is waiting on this object (see `parcThreadPool_Wait)`.
+ * If any threads are waiting on this object, one of them is chosen to be awakened.
+ * The choice is arbitrary and occurs at the discretion of the underlying implementation.
+ *
+ * The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
+ * The awakened thread will compete in the usual manner with any other threads that might be actively
+ * competing to synchronize on this object;
+ * for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
+ *
+ * @param [in] object A pointer to a valid PARCThreadPool instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcThreadPool_Lock(object)) {
+ * parcThreadPool_Notify(object);
+ * parcThreadPool_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotify(parcThreadPool, PARCThreadPool);
+
+/**
+ * Wakes up all threads that are waiting on the given object's lock.
+ *
+ * A thread waits on an object by calling one of the wait methods, `parcThreadPool_Wait`, `parcThreadPool_WaitFor`, `parcThreadPool_WaitUntil`.
+ * The awakened threads will proceed after the current thread relinquishes the lock on the given object.
+ * The awakened threads will compete in the usual manner with any other threads that might be actively competing
+ * to synchronize on this object.
+ * Awakened threads have no priority between them in being the next thread to lock this object.
+ *
+ * This method can only be called by a thread that is the owner of this object's lock.
+ *
+ * @param [in] object A pointer to a valid `PARCThreadPool` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcThreadPool_Lock(object)) {
+ * parcThreadPool_NotifyAll(object);
+ * parcThreadPool_Unlock(object);
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementNotifyAll(parcThreadPool, PARCThreadPool);
+
+/**
+ * Causes the calling thread to wait until either another thread invokes the parcThreadPool_Notify() function on the same object.
+ * *
+ * @param [in] object A pointer to a valid `PARCThreadPool` instance.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * parcThreadPool_Wait(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementWait(parcThreadPool, PARCThreadPool);
+
+/**
+ * Obtain the lock on the given `PARCThreadPool` instance.
+ *
+ * If the lock is already held by another thread, this function will block.
+ * If the lock is aleady held by the current thread, this function will return `false`.
+ *
+ * Implementors must avoid deadlock by attempting to lock the object a second time within the same calling thread.
+ *
+ * @param [in] object A pointer to a valid `PARCThreadPool` instance.
+ *
+ * @return true The lock was obtained successfully.
+ * @return false The lock is already held by the current thread, or the `PARCThreadPool` is invalid.
+ *
+ * Example:
+ * @code
+ * {
+ * if (parcThreadPool_Lock(object)) {
+ *
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementLock(parcThreadPool, PARCThreadPool);
+
+/**
+ * Try to obtain the advisory lock on the given PARCThreadPool instance.
+ *
+ * Once the lock is obtained, the caller must release the lock as soon as possible.
+ *
+ * @param [in] object A pointer to a valid PARCThreadPool instance.
+ *
+ * @return true The PARCThreadPool is locked.
+ * @return false The PARCThreadPool is unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcThreadPool_TryLock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementTryLock(parcThreadPool, PARCThreadPool);
+
+/**
+ * Try to unlock the advisory lock on the given `PARCThreadPool` instance.
+ *
+ * @param [in] object A pointer to a valid `PARCThreadPool` instance.
+ *
+ * @return true The `PARCThreadPool` was locked and now is unlocked.
+ * @return false The `PARCThreadPool` was not locked and remains unlocked.
+ *
+ * Example:
+ * @code
+ * {
+ * parcThreadPool_Unlock(object);
+ * }
+ * @endcode
+ */
+parcObject_ImplementUnlock(parcThreadPool, PARCThreadPool);
+
+/**
+ * Determine if the advisory lock on the given `PARCThreadPool` instance is locked.
+ *
+ * @param [in] object A pointer to a valid `PARCThreadPool` instance.
+ *
+ * @return true The `PARCThreadPool` is locked.
+ * @return false The `PARCThreadPool` is unlocked.
+ * Example:
+ * @code
+ * {
+ * if (parcThreadPool_IsLocked(object)) {
+ * ...
+ * }
+ * }
+ * @endcode
+ */
+parcObject_ImplementIsLocked(parcThreadPool, PARCThreadPool);
+
+/**
+ * Sets the policy governing whether core threads may time out and terminate if no tasks arrive within the keep-alive time, being replaced if needed when new tasks arrive.
+ */
+void parcThreadPool_SetAllowCoreThreadTimeOut(PARCThreadPool *pool, bool value);
+
+/**
+ * Returns true if this pool allows core threads to time out and terminate if no tasks arrive within the keepAlive time, being replaced if needed when new tasks arrive.
+ */
+bool parcThreadPool_GetAllowsCoreThreadTimeOut(const PARCThreadPool *pool);
+
+/**
+ * Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, whichever happens first.
+ */
+bool parcThreadPool_AwaitTermination(PARCThreadPool *pool, PARCTimeout *timeout);
+
+/**
+ * Executes the given task sometime in the future.
+ */
+bool parcThreadPool_Execute(PARCThreadPool *pool, PARCFutureTask *task);
+
+/**
+ * Returns the approximate number of threads that are actively executing tasks.
+ */
+int parcThreadPool_GetActiveCount(const PARCThreadPool *pool);
+
+/**
+ * Returns the approximate total number of tasks that have completed execution.
+ */
+uint64_t parcThreadPool_GetCompletedTaskCount(const PARCThreadPool *pool);
+
+/**
+ * Returns the core number of threads.
+ */
+int parcThreadPool_GetCorePoolSize(const PARCThreadPool *pool);
+
+/**
+ * Returns the thread keep-alive time, which is the amount of time that threads in excess of the core pool size may remain idle before being terminated.
+ */
+PARCTimeout *parcThreadPool_GetKeepAliveTime(const PARCThreadPool *pool);
+
+/**
+ * Returns the largest number of threads that have ever simultaneously been in the pool.
+ */
+int parcThreadPool_GetLargestPoolSize(const PARCThreadPool *pool);
+
+/**
+ * Returns the maximum allowed number of threads.
+ */
+int parcThreadPool_GetMaximumPoolSize(const PARCThreadPool *pool);
+
+/**
+ * Returns the current number of threads in the pool.
+ */
+int parcThreadPool_GetPoolSize(const PARCThreadPool *pool);
+
+/**
+ * Returns the task queue used by this executor.
+ */
+PARCLinkedList *parcThreadPool_GetQueue(const PARCThreadPool *pool);
+
+/**
+ * Returns the approximate total number of tasks that have ever been scheduled for execution.
+ */
+long parcThreadPool_GetTaskCount(const PARCThreadPool *pool);
+
+/**
+ * Returns true if this executor has been shut down.
+ */
+bool parcThreadPool_IsShutdown(const PARCThreadPool *pool);
+
+/**
+ * Returns true if all tasks have completed following shut down.
+ */
+bool parcThreadPool_IsTerminated(const PARCThreadPool *pool);
+
+/**
+ * Returns true if this executor is in the process of terminating after shutdown() or shutdownNow() but has not completely terminated.
+ */
+bool parcThreadPool_IsTerminating(const PARCThreadPool *pool);
+
+/**
+ * Starts all core threads, causing them to idly wait for work.
+ */
+int parcThreadPool_PrestartAllCoreThreads(PARCThreadPool *pool);
+
+/**
+ * Starts a core thread, causing it to idly wait for work.
+ */
+bool parcThreadPool_PrestartCoreThread(PARCThreadPool *pool);
+
+/**
+ * Tries to remove from the work queue all Future tasks that have been cancelled.
+ */
+void parcThreadPool_Purge(PARCThreadPool *pool);
+
+/**
+ * Removes this task from the executor's internal queue if it is present, thus causing it not to be run if it has not already started.
+ */
+bool parcThreadPool_Remove(PARCThreadPool *pool, PARCFutureTask *task);
+
+/**
+ * Sets the core number of threads.
+ */
+void parcThreadPool_SetCorePoolSize(PARCThreadPool *pool, int corePoolSize);
+
+/**
+ * Sets the time limit for which threads may remain idle before being terminated.
+ */
+void parcThreadPool_SetKeepAliveTime(PARCThreadPool *pool, PARCTimeout *timeout);
+
+/**
+ * Sets the maximum allowed number of threads.
+ */
+void parcThreadPool_SetMaximumPoolSize(PARCThreadPool *pool, int maximumPoolSize);
+
+/**
+ * Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.
+ */
+void parcThreadPool_Shutdown(PARCThreadPool *pool);
+
+/**
+ * Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.
+ */
+PARCLinkedList *parcThreadPool_ShutdownNow(PARCThreadPool *pool);
+#endif
diff --git a/libparc/parc/concurrent/parc_Timeout.c b/libparc/parc/concurrent/parc_Timeout.c
new file mode 100755
index 00000000..4ea03977
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Timeout.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include <parc/concurrent/parc_Timeout.h>
+
+
+bool
+parcTimeout_Equals(PARCTimeout x, PARCTimeout y)
+{
+ return x == y;
+}
diff --git a/libparc/parc/concurrent/parc_Timeout.h b/libparc/parc/concurrent/parc_Timeout.h
new file mode 100644
index 00000000..9edc24a0
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Timeout.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.
+ */
+
+/**
+ * @ingroup threading
+ *
+ */
+#ifndef parc_Timeout_h
+#define parc_Timeout_h
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef uint64_t PARCTimeout;
+
+/**
+ * @def PARCTimeout_Never
+ * This represents a timeout that will never happen.
+ */
+#define PARCTimeout_Never NULL
+
+/*
+ * @def PARCTimeout_Immediate
+ * This represents a timeout that immediately happens.
+ * Equivalent to parcTimeout_NanoSeconds(0)
+ */
+#define PARCTimeout_Immediate (&(PARCTimeout) { 0 })
+
+/*
+ * @def PARCTimeout_NanoSeconds
+ * This represents a timeout that will occur in the specified number of nanoseconds.
+ */
+#define parcTimeout_NanoSeconds(_nsec_) (&(PARCTimeout) { _nsec_ })
+
+/*
+ * @def PARCTimeout_MicroSeconds
+ * This represents a timeout that will occur in the specified number of microseconds.
+ */
+#define parcTimeout_MicroSeconds(_usec_) parcTimeout_NanoSeconds(_usec_ * 1000)
+
+/*
+ * @def PARCTimeout_MilliSeconds
+ * This represents a timeout that will occur in the specified number of microseconds.
+ */
+#define parcTimeout_MilliSeconds(_msec_) parcTimeout_MicroSeconds(_msec_ * 1000)
+
+/**
+ * Determine if two `PARCTimeout` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCTimeout` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcTimeout_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcTimeout_Equals(x, y)` must return true if and only if
+ * `parcTimeout_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcTimeout_Equals(x, y)` returns true and
+ * `parcTimeout_Equals(y, z)` returns true,
+ * then `parcTimeout_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcTimeout_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcTimeout_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A valid PARCTimeout instance.
+ * @param [in] y A valid PARCTimeout instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimeout *a = parcTimeout_Create();
+ * PARCTimeout *b = parcTimeout_Create();
+ *
+ * if (parcTimeout_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcTimeout_Release(&a);
+ * parcTimeout_Release(&b);
+ * }
+ * @endcode
+ * @see parcTimeout_HashCode
+ */
+bool parcTimeout_Equals(PARCTimeout x, PARCTimeout y);
+
+/**
+ * Predicate function returning true if the given timeout represents an infinite delay.
+ *
+ * @param [in] timeout A pointer to a valid PARCTimeout value.
+ *
+ * @return true The given timeout represents an infinite delay.
+ */
+static inline bool
+parcTimeout_IsNever(const PARCTimeout *timeout)
+{
+ return (timeout == PARCTimeout_Never);
+}
+
+/**
+ * Predicate function returning true if the given timeout represents an immediate, no-delay timeout.
+ *
+ * @param [in] timeout A pointer to a valid PARCTimeout value.
+ *
+ * @return true The given timeout represents an immediate, no-delay timeout.
+ */
+static inline bool
+parcTimeout_IsImmediate(const PARCTimeout *timeout)
+{
+ return parcTimeout_IsNever(timeout) ? false : (*timeout == 0);
+}
+
+/**
+ * Return the number of nano-seconds in the given PARCTimeout instance.
+ *
+ * If the PARCTimeout is never (`parcTimeout_IsNever` returns `true`), the returned value is UINT64_MAX.
+ *
+ * @param [in] timeout A pointer to a valid PARCTimeout value.
+ *
+ * @return The number of nano-seconds in the given PARCTimeout instance, UINT64_MAX.
+ */
+static inline uint64_t
+parcTimeout_InNanoSeconds(const PARCTimeout *timeout)
+{
+ return parcTimeout_IsNever(timeout) ? UINT64_MAX : *timeout;
+}
+#endif /* parc_Timeout_h */
diff --git a/libparc/parc/concurrent/parc_Timer.c b/libparc/parc/concurrent/parc_Timer.c
new file mode 100755
index 00000000..e6d84de4
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Timer.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 <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include "parc_Timer.h"
+
+struct PARCTimer {
+ int delay;
+};
+
+static void
+_parcTimer_Finalize(PARCTimer **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCTimer pointer.");
+
+
+ /* cleanup the instance fields here */
+}
+
+parcObject_ImplementAcquire(parcTimer, PARCTimer);
+
+parcObject_ImplementRelease(parcTimer, PARCTimer);
+
+parcObject_ExtendPARCObject(PARCTimer, _parcTimer_Finalize, parcTimer_Copy, parcTimer_ToString, parcTimer_Equals, parcTimer_Compare, parcTimer_HashCode, parcTimer_ToJSON);
+
+
+void
+parcTimer_AssertValid(const PARCTimer *instance)
+{
+ assertTrue(parcTimer_IsValid(instance),
+ "PARCTimer is not valid.");
+}
+
+PARCTimer *
+parcTimer_Create(void)
+{
+ PARCTimer *result = parcObject_CreateInstance(PARCTimer);
+
+ if (result != NULL) {
+ }
+
+ return result;
+}
+
+int
+parcTimer_Compare(const PARCTimer *instance, const PARCTimer *other)
+{
+ int result = 0;
+
+ return result;
+}
+
+PARCTimer *
+parcTimer_Copy(const PARCTimer *original)
+{
+ PARCTimer *result = parcTimer_Create();
+
+ return result;
+}
+
+void
+parcTimer_Display(const PARCTimer *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCTimer@%p {", instance);
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcTimer_Equals(const PARCTimer *x, const PARCTimer *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ return true;
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcTimer_HashCode(const PARCTimer *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+parcTimer_IsValid(const PARCTimer *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcTimer_ToJSON(const PARCTimer *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ if (result != NULL) {
+ }
+
+ return result;
+}
+
+char *
+parcTimer_ToString(const PARCTimer *instance)
+{
+ char *result = parcMemory_Format("PARCTimer@%p\n", instance);
+
+ return result;
+}
+
+void
+parcTimer_Cancel(PARCTimer *timer)
+{
+}
+
+int
+parcTimer_Purge(PARCTimer *timer)
+{
+ return 0;
+}
+
+void
+parcTimer_ScheduleAtTime(PARCTimer *timer, PARCFutureTask *task, time_t absoluteTime)
+{
+}
+
+void
+parcTimer_ScheduleAtTimeAndRepeat(PARCTimer *timer, PARCFutureTask *task, time_t firstTime, long period)
+{
+}
+
+void
+parcTimer_ScheduleAfterDelay(PARCTimer *timer, PARCFutureTask *task, long delay)
+{
+}
+
+void
+parcTimer_ScheduleAfterDelayAndRepeat(PARCTimer *timer, PARCFutureTask *task, long delay, long period)
+{
+}
+
diff --git a/libparc/parc/concurrent/parc_Timer.h b/libparc/parc/concurrent/parc_Timer.h
new file mode 100755
index 00000000..416bfba4
--- /dev/null
+++ b/libparc/parc/concurrent/parc_Timer.h
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Timer.h
+ * @ingroup threading
+ * @brief A facility for threads to schedule tasks for future execution in a background thread.
+ *
+ * Tasks may be scheduled for one-time execution, or for repeated execution at regular intervals.
+ *
+ * Corresponding to each Timer object is a single background thread that is used to execute all of the timer's tasks,
+ * sequentially. Timer tasks should complete quickly.
+ * If a timer task takes excessive time to complete, it "hogs" the timer's task execution thread.
+ * This can, in turn, delay the execution of subsequent tasks,
+ * which may "bunch up" and execute in rapid succession when (and if) the offending task finally completes.
+ *
+ * After the last live reference to a Timer object goes away and all outstanding tasks have completed execution,
+ * the timer's task execution thread terminates gracefully (and becomes subject to garbage collection).
+ * However, this can take arbitrarily long to occur.
+ * By default, the task execution thread does not run as a daemon thread,
+ * so it is capable of keeping an application from terminating.
+ * If a caller wants to terminate a timer's task execution thread rapidly, the caller should invoke the timer's cancel method.
+ *
+ * If the timer's task execution thread terminates unexpectedly,
+ * for example, because its stop method is invoked,
+ * any further attempt to schedule a task on the timer will result in an IllegalStateException,
+ * as if the timer's cancel method had been invoked.
+ *
+ * This class is thread-safe: multiple threads can share a single Timer object without the need for external synchronization.
+ *
+ * This class does not offer real-time guarantees: it schedules tasks using the Object.wait(long) method.
+ *
+ */
+#ifndef PARCLibrary_parc_Timer
+#define PARCLibrary_parc_Timer
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/concurrent/parc_FutureTask.h>
+
+struct PARCTimer;
+typedef struct PARCTimer PARCTimer;
+
+/**
+ * Increase the number of references to a `PARCTimer` instance.
+ *
+ * Note that new `PARCTimer` is not created,
+ * only that the given `PARCTimer` reference count is incremented.
+ * Discard the reference by invoking `parcTimer_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCTimer instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * PARCTimer *b = parcTimer_Acquire();
+ *
+ * parcTimer_Release(&a);
+ * parcTimer_Release(&b);
+ * }
+ * @endcode
+ */
+PARCTimer *parcTimer_Acquire(const PARCTimer *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcTimer_OptionalAssertValid(_instance_)
+#else
+# define parcTimer_OptionalAssertValid(_instance_) parcTimer_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCTimer` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCTimer instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * parcTimer_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcTimer_Release(&b);
+ * }
+ * @endcode
+ */
+void parcTimer_AssertValid(const PARCTimer *instance);
+
+/**
+ * Create an instance of PARCTimer
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCTimer instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * parcTimer_Release(&a);
+ * }
+ * @endcode
+ */
+PARCTimer *parcTimer_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 PARCTimer instance.
+ * @param [in] other A pointer to a valid PARCTimer 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
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ * PARCTimer *b = parcTimer_Create();
+ *
+ * if (parcTimer_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcTimer_Release(&a);
+ * parcTimer_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcTimer_Equals
+ */
+int parcTimer_Compare(const PARCTimer *instance, const PARCTimer *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 PARCTimer instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCTimer` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * PARCTimer *copy = parcTimer_Copy(&b);
+ *
+ * parcTimer_Release(&b);
+ * parcTimer_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCTimer *parcTimer_Copy(const PARCTimer *original);
+
+/**
+ * Print a human readable representation of the given `PARCTimer`.
+ *
+ * @param [in] instance A pointer to a valid PARCTimer instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * parcTimer_Display(a, 0);
+ *
+ * parcTimer_Release(&a);
+ * }
+ * @endcode
+ */
+void parcTimer_Display(const PARCTimer *instance, int indentation);
+
+/**
+ * Determine if two `PARCTimer` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCTimer` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcTimer_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcTimer_Equals(x, y)` must return true if and only if
+ * `parcTimer_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcTimer_Equals(x, y)` returns true and
+ * `parcTimer_Equals(y, z)` returns true,
+ * then `parcTimer_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcTimer_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcTimer_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCTimer instance.
+ * @param [in] y A pointer to a valid PARCTimer instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ * PARCTimer *b = parcTimer_Create();
+ *
+ * if (parcTimer_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcTimer_Release(&a);
+ * parcTimer_Release(&b);
+ * }
+ * @endcode
+ * @see parcTimer_HashCode
+ */
+bool parcTimer_Equals(const PARCTimer *x, const PARCTimer *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 parcTimer_Equals} method,
+ * then calling the {@link parcTimer_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 parcTimer_Equals} function,
+ * then calling the `parcTimer_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCTimer instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * PARCHashCode hashValue = parcTimer_HashCode(buffer);
+ * parcTimer_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcTimer_HashCode(const PARCTimer *instance);
+
+/**
+ * Determine if an instance of `PARCTimer` 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 PARCTimer instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * if (parcTimer_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcTimer_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcTimer_IsValid(const PARCTimer *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCTimer` 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
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * parcTimer_Release(&a);
+ * }
+ * @endcode
+ */
+void parcTimer_Release(PARCTimer **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCTimer 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
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * PARCJSON *json = parcTimer_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcTimer_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcTimer_ToJSON(const PARCTimer *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCTimer`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCTimer 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
+ * {
+ * PARCTimer *a = parcTimer_Create();
+ *
+ * char *string = parcTimer_ToString(a);
+ *
+ * parcTimer_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcTimer_Display
+ */
+char *parcTimer_ToString(const PARCTimer *timer);
+
+/**
+ * Terminates this timer, discarding any currently scheduled tasks.
+ *
+ * Does not interfere with a currently executing task (if it exists).
+ * Once a timer has been terminated, its execution thread terminates gracefully,
+ * and no more tasks may be scheduled on it.
+ *
+ * Note that calling this method from within the run method of a timer task that was invoked
+ * by this timer absolutely guarantees that the ongoing task execution is the last task execution
+ * that will ever be performed by this timer.
+ *
+ * This method may be called repeatedly; the second and subsequent calls have no effect.
+ */
+void parcTimer_Cancel(PARCTimer *timer);
+
+/**
+ * Removes all cancelled tasks from this timer's task queue.
+ *
+ * Calling this method has no effect on the behavior of the timer,
+ * but eliminates the references to the cancelled tasks from the queue.
+ * If there are no external references to these tasks, they become eligible for garbage collection.
+ *
+ * Most programs will have no need to call this method.
+ * It is designed for use by the rare application that cancels a large number of tasks.
+ * Calling this method trades time for space: the runtime of the method may be proportional to
+ * n + c log n, where n is the number of tasks in the queue and c is the number of cancelled tasks.
+ *
+ * It is permissible to call this method from within a task scheduled on this timer.
+ *
+ * @returns the number of tasks removed from the queue.
+ */
+int parcTimer_Purge(PARCTimer *timer);
+
+/**
+ * Schedules the specified task for execution at the specified time.
+ */
+void parcTimer_ScheduleAtTime(PARCTimer *timer, PARCFutureTask *task, time_t absoluteTime);
+
+/**
+ * Schedules the specified task for repeated fixed-delay execution, beginning at the specified time.
+ */
+void parcTimer_ScheduleAtTimeAndRepeat(PARCTimer *timer, PARCFutureTask *task, time_t firstTime, long period);
+
+/**
+ * Schedules the specified task for execution after the specified delay.
+ */
+void parcTimer_ScheduleAfterDelay(PARCTimer *timer, PARCFutureTask *task, long delay);
+
+/**
+ * Schedules the specified task for repeated fixed-delay execution, beginning after the specified delay.
+ */
+void parcTimer_ScheduleAfterDelayAndRepeat(PARCTimer *timer, PARCFutureTask *task, long delay, long period);
+#endif
diff --git a/libparc/parc/concurrent/test/.gitignore b/libparc/parc/concurrent/test/.gitignore
new file mode 100644
index 00000000..2c9fe4f5
--- /dev/null
+++ b/libparc/parc/concurrent/test/.gitignore
@@ -0,0 +1,10 @@
+test_parc_Notifier
+test_parc_RingBuffer_1x1
+test_parc_RingBuffer_NxM
+test_parc_AtomicUint64
+test_parc_Barrier
+test_parc_AtomicUint16
+test_parc_AtomicUint32
+test_parc_AtomicUint8
+test_parc_Synchronizer
+test_parc_Lock
diff --git a/libparc/parc/concurrent/test/CMakeLists.txt b/libparc/parc/concurrent/test/CMakeLists.txt
new file mode 100644
index 00000000..092d0202
--- /dev/null
+++ b/libparc/parc/concurrent/test/CMakeLists.txt
@@ -0,0 +1,25 @@
+set(TestsExpectedToPass
+ test_parc_AtomicUint16
+ test_parc_AtomicUint32
+ test_parc_AtomicUint64
+ test_parc_AtomicUint8
+ test_parc_FutureTask
+ test_parc_Lock
+ test_parc_Notifier
+ test_parc_RingBuffer_1x1
+ test_parc_RingBuffer_NxM
+ test_parc_ScheduledTask
+ test_parc_ScheduledThreadPool
+ test_parc_Synchronizer
+ test_parc_Thread
+ test_parc_ThreadPool
+ test_parc_Timer
+ )
+
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
diff --git a/libparc/parc/concurrent/test/test_parc_AtomicUint16.c b/libparc/parc/concurrent/test/test_parc_AtomicUint16.c
new file mode 100644
index 00000000..ed97cc95
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_AtomicUint16.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include "../parc_AtomicUint16.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <inttypes.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_AtomicUint16)
+{
+ // 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);
+ LONGBOW_RUN_TEST_FIXTURE(Macros);
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_AtomicUint16)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_AtomicUint16)
+{
+ 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)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+ assertNotNull(instance, "Expeced non-null result from parcAtomicUint16_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcAtomicUint16_Acquire, instance);
+
+ parcAtomicUint16_Release(&instance);
+ assertNull(instance, "Expected null result from parcAtomicUint16_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint16_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint16_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint16_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint16_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint16_IsValid);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint16_SubtractImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint16_AddImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint16_CompareAndSwapImpl);
+}
+
+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, parcAtomicUint16_Compare)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+ PARCAtomicUint16 *high = parcAtomicUint16_Create(8);
+ PARCAtomicUint16 *low = parcAtomicUint16_Create(6);
+ PARCAtomicUint16 *equal = parcAtomicUint16_Create(7);
+
+ int actual = parcAtomicUint16_Compare(instance, high);
+ assertTrue(actual < 0, "Expected < 0");
+ actual = parcAtomicUint16_Compare(instance, low);
+ assertTrue(actual > 0, "Expected > 0");
+ actual = parcAtomicUint16_Compare(instance, equal);
+ assertTrue(actual == 0, "Expected == 0");
+
+ parcAtomicUint16_Release(&instance);
+ parcAtomicUint16_Release(&high);
+ parcAtomicUint16_Release(&low);
+ parcAtomicUint16_Release(&equal);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint16_Copy)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+ PARCAtomicUint16 *copy = parcAtomicUint16_Copy(instance);
+
+ assertTrue(parcAtomicUint16_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcAtomicUint16_Release(&instance);
+ parcAtomicUint16_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint16_Equals)
+{
+ PARCAtomicUint16 *x = parcAtomicUint16_Create(7);
+ PARCAtomicUint16 *y = parcAtomicUint16_Create(7);
+ PARCAtomicUint16 *z = parcAtomicUint16_Create(7);
+ PARCAtomicUint16 *u1 = parcAtomicUint16_Create(6);
+
+ parcObjectTesting_AssertEquals(x, y, z, u1, NULL);
+
+ parcAtomicUint16_Release(&x);
+ parcAtomicUint16_Release(&y);
+ parcAtomicUint16_Release(&z);
+ parcAtomicUint16_Release(&u1);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint16_HashCode)
+{
+ PARCAtomicUint16 *x = parcAtomicUint16_Create(7);
+ parcAtomicUint16_HashCode(x);
+ parcAtomicUint16_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint16_IsValid)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+ assertTrue(parcAtomicUint16_IsValid(instance), "Expected parcAtomicUint16_Create to result in a valid instance.");
+
+ parcAtomicUint16_Release(&instance);
+ assertFalse(parcAtomicUint16_IsValid(instance), "Expected parcAtomicUint16_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint16_SubtractImpl)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+
+ parcAtomicUint16_SubtractImpl(instance, 1);
+
+ uint16_t actual = parcAtomicUint16_GetValue(instance);
+
+ assertTrue(actual == 6, "Expected 6, actual %" PRIu16, actual);
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint16_AddImpl)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+
+ parcAtomicUint16_AddImpl(instance, 1);
+
+ uint16_t actual = parcAtomicUint16_GetValue(instance);
+
+ assertTrue(actual == 8, "Expected 8, actual %" PRIu16, actual);
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint16_CompareAndSwapImpl)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+
+ bool actual = parcAtomicUint16_CompareAndSwapImpl(instance, 7, 8);
+
+ assertTrue(actual, "Expected parcAtomicUint16_CompareAndSwapImpl to return true");
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Macros)
+{
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint16_Subtract);
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint16_Add);
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint16_CompareAndSwap);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Macros)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Macros)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint16_Subtract)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+
+ parcAtomicUint16_Subtract(instance, 1);
+
+ uint16_t actual = parcAtomicUint16_GetValue(instance);
+
+ assertTrue(actual == 6, "Expected 6, actual %" PRIu16, actual);
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint16_Add)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+
+ parcAtomicUint16_Add(instance, 1);
+
+ uint16_t actual = parcAtomicUint16_GetValue(instance);
+
+ assertTrue(actual == 8, "Expected 8, actual %" PRIu16, actual);
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint16_CompareAndSwap)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(7);
+
+ bool actual = parcAtomicUint16_CompareAndSwap(instance, 7, 8);
+
+ assertTrue(actual, "Expected parcAtomicUint16_CompareAndSwap to return true");
+ parcAtomicUint16_Release(&instance);
+}
+
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint16_Subtract_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint16_Add_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint16_CompareAndSwap_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint16_SubtractImpl);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint16_AddImpl);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint16_CompareAndSwapImpl);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint16_Subtract_MACRO)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(65535);
+
+ while (parcAtomicUint16_Subtract(instance, 1) > 0) {
+ ;
+ }
+
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint16_Add_MACRO)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(1);
+
+ while (parcAtomicUint16_Add(instance, 1) < 65535) {
+ ;
+ }
+
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint16_CompareAndSwap_MACRO)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(0);
+
+ for (uint16_t i = 0; i < 65535; i++) {
+ bool actual = parcAtomicUint16_CompareAndSwap(instance, i, i + 1);
+ assertTrue(actual, "Expected parcAtomicUint16_CompareAndSwap to return true");
+ }
+
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint16_SubtractImpl)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(65535);
+
+ while (parcAtomicUint16_SubtractImpl(instance, 1) > 0) {
+ ;
+ }
+
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint16_AddImpl)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(1);
+
+ while (parcAtomicUint16_AddImpl(instance, 1) < 65535) {
+ ;
+ }
+
+ parcAtomicUint16_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint16_CompareAndSwapImpl)
+{
+ PARCAtomicUint16 *instance = parcAtomicUint16_Create(0);
+
+ for (uint16_t i = 0; i < 65535; i++) {
+ bool actual = parcAtomicUint16_CompareAndSwapImpl(instance, i, i + 1);
+ assertTrue(actual, "Expected parcAtomicUint16_CompareAndSwapImpl to return true");
+ }
+
+ parcAtomicUint16_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_AtomicUint16);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_AtomicUint32.c b/libparc/parc/concurrent/test/test_parc_AtomicUint32.c
new file mode 100644
index 00000000..1649cf1c
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_AtomicUint32.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include "../parc_AtomicUint64.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <inttypes.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_AtomicUint64)
+{
+ // 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);
+ LONGBOW_RUN_TEST_FIXTURE(Macros);
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_AtomicUint64)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_AtomicUint64)
+{
+ 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)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ assertNotNull(instance, "Expeced non-null result from parcAtomicUint64_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcAtomicUint64_Acquire, instance);
+
+ parcAtomicUint64_Release(&instance);
+ assertNull(instance, "Expected null result from parcAtomicUint64_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_IsValid);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_SubtractImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_AddImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_CompareAndSwapImpl);
+}
+
+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, parcAtomicUint64_Compare)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *high = parcAtomicUint64_Create(8);
+ PARCAtomicUint64 *low = parcAtomicUint64_Create(6);
+ PARCAtomicUint64 *equal = parcAtomicUint64_Create(7);
+
+ int actual = parcAtomicUint64_Compare(instance, high);
+ assertTrue(actual < 0, "Expected < 0");
+ actual = parcAtomicUint64_Compare(instance, low);
+ assertTrue(actual > 0, "Expected > 0");
+ actual = parcAtomicUint64_Compare(instance, equal);
+ assertTrue(actual == 0, "Expected == 0");
+
+ parcAtomicUint64_Release(&instance);
+ parcAtomicUint64_Release(&high);
+ parcAtomicUint64_Release(&low);
+ parcAtomicUint64_Release(&equal);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_Copy)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *copy = parcAtomicUint64_Copy(instance);
+
+ assertTrue(parcAtomicUint64_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcAtomicUint64_Release(&instance);
+ parcAtomicUint64_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_Equals)
+{
+ PARCAtomicUint64 *x = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *y = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *z = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *u1 = parcAtomicUint64_Create(6);
+
+ parcObjectTesting_AssertEquals(x, y, z, u1, NULL);
+
+ parcAtomicUint64_Release(&x);
+ parcAtomicUint64_Release(&y);
+ parcAtomicUint64_Release(&z);
+ parcAtomicUint64_Release(&u1);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_HashCode)
+{
+ PARCAtomicUint64 *x = parcAtomicUint64_Create(7);
+ parcAtomicUint64_HashCode(x);
+ parcAtomicUint64_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_IsValid)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ assertTrue(parcAtomicUint64_IsValid(instance), "Expected parcAtomicUint64_Create to result in a valid instance.");
+
+ parcAtomicUint64_Release(&instance);
+ assertFalse(parcAtomicUint64_IsValid(instance), "Expected parcAtomicUint64_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_SubtractImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ parcAtomicUint64_SubtractImpl(instance, 1);
+
+ uint64_t actual = parcAtomicUint64_GetValue(instance);
+
+ assertTrue(actual == 6, "Expected 6, actual %" PRIu64, actual);
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_AddImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ parcAtomicUint64_AddImpl(instance, 1);
+
+ uint64_t actual = parcAtomicUint64_GetValue(instance);
+
+ assertTrue(actual == 8, "Expected 8, actual %" PRIu64, actual);
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_CompareAndSwapImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ bool actual = parcAtomicUint64_CompareAndSwapImpl(instance, 7, 8);
+
+ assertTrue(actual, "Expected parcAtomicUint64_CompareAndSwapImpl to return true");
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Macros)
+{
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint64_Subtract);
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint64_Add);
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint64_CompareAndSwap);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Macros)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Macros)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint64_Subtract)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ parcAtomicUint64_Subtract(instance, 1);
+
+ uint64_t actual = parcAtomicUint64_GetValue(instance);
+
+ assertTrue(actual == 6, "Expected 6, actual %" PRIu64, actual);
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint64_Add)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ parcAtomicUint64_Add(instance, 1);
+
+ uint64_t actual = parcAtomicUint64_GetValue(instance);
+
+ assertTrue(actual == 8, "Expected 8, actual %" PRIu64, actual);
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint64_CompareAndSwap)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ bool actual = parcAtomicUint64_CompareAndSwap(instance, 7, 8);
+
+ assertTrue(actual, "Expected parcAtomicUint64_CompareAndSwap to return true");
+ parcAtomicUint64_Release(&instance);
+}
+
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_Subtract_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_Add_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_CompareAndSwap_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_SubtractImpl);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_AddImpl);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_CompareAndSwapImpl);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_Subtract_MACRO)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(100000000);
+
+ while (parcAtomicUint64_Subtract(instance, 1) > 0) {
+ ;
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_Add_MACRO)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(1);
+
+ while (parcAtomicUint64_Add(instance, 1) < 100000000) {
+ ;
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_CompareAndSwap_MACRO)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(0);
+
+ for (uint64_t i = 0; i < 100000000; i++) {
+ bool actual = parcAtomicUint64_CompareAndSwap(instance, i, i + 1);
+ assertTrue(actual, "Expected parcAtomicUint64_CompareAndSwap to return true");
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_SubtractImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(100000000);
+
+ while (parcAtomicUint64_SubtractImpl(instance, 1) > 0) {
+ ;
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_AddImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(1);
+
+ while (parcAtomicUint64_AddImpl(instance, 1) < 100000000) {
+ ;
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_CompareAndSwapImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(0);
+
+ for (uint64_t i = 0; i < 100000000; i++) {
+ bool actual = parcAtomicUint64_CompareAndSwapImpl(instance, i, i + 1);
+ assertTrue(actual, "Expected parcAtomicUint64_CompareAndSwapImpl to return true");
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_AtomicUint64);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_AtomicUint64.c b/libparc/parc/concurrent/test/test_parc_AtomicUint64.c
new file mode 100644
index 00000000..1649cf1c
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_AtomicUint64.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include "../parc_AtomicUint64.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <inttypes.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_AtomicUint64)
+{
+ // 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);
+ LONGBOW_RUN_TEST_FIXTURE(Macros);
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_AtomicUint64)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_AtomicUint64)
+{
+ 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)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ assertNotNull(instance, "Expeced non-null result from parcAtomicUint64_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcAtomicUint64_Acquire, instance);
+
+ parcAtomicUint64_Release(&instance);
+ assertNull(instance, "Expected null result from parcAtomicUint64_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_IsValid);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_SubtractImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_AddImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint64_CompareAndSwapImpl);
+}
+
+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, parcAtomicUint64_Compare)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *high = parcAtomicUint64_Create(8);
+ PARCAtomicUint64 *low = parcAtomicUint64_Create(6);
+ PARCAtomicUint64 *equal = parcAtomicUint64_Create(7);
+
+ int actual = parcAtomicUint64_Compare(instance, high);
+ assertTrue(actual < 0, "Expected < 0");
+ actual = parcAtomicUint64_Compare(instance, low);
+ assertTrue(actual > 0, "Expected > 0");
+ actual = parcAtomicUint64_Compare(instance, equal);
+ assertTrue(actual == 0, "Expected == 0");
+
+ parcAtomicUint64_Release(&instance);
+ parcAtomicUint64_Release(&high);
+ parcAtomicUint64_Release(&low);
+ parcAtomicUint64_Release(&equal);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_Copy)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *copy = parcAtomicUint64_Copy(instance);
+
+ assertTrue(parcAtomicUint64_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcAtomicUint64_Release(&instance);
+ parcAtomicUint64_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_Equals)
+{
+ PARCAtomicUint64 *x = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *y = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *z = parcAtomicUint64_Create(7);
+ PARCAtomicUint64 *u1 = parcAtomicUint64_Create(6);
+
+ parcObjectTesting_AssertEquals(x, y, z, u1, NULL);
+
+ parcAtomicUint64_Release(&x);
+ parcAtomicUint64_Release(&y);
+ parcAtomicUint64_Release(&z);
+ parcAtomicUint64_Release(&u1);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_HashCode)
+{
+ PARCAtomicUint64 *x = parcAtomicUint64_Create(7);
+ parcAtomicUint64_HashCode(x);
+ parcAtomicUint64_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_IsValid)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+ assertTrue(parcAtomicUint64_IsValid(instance), "Expected parcAtomicUint64_Create to result in a valid instance.");
+
+ parcAtomicUint64_Release(&instance);
+ assertFalse(parcAtomicUint64_IsValid(instance), "Expected parcAtomicUint64_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_SubtractImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ parcAtomicUint64_SubtractImpl(instance, 1);
+
+ uint64_t actual = parcAtomicUint64_GetValue(instance);
+
+ assertTrue(actual == 6, "Expected 6, actual %" PRIu64, actual);
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_AddImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ parcAtomicUint64_AddImpl(instance, 1);
+
+ uint64_t actual = parcAtomicUint64_GetValue(instance);
+
+ assertTrue(actual == 8, "Expected 8, actual %" PRIu64, actual);
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint64_CompareAndSwapImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ bool actual = parcAtomicUint64_CompareAndSwapImpl(instance, 7, 8);
+
+ assertTrue(actual, "Expected parcAtomicUint64_CompareAndSwapImpl to return true");
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Macros)
+{
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint64_Subtract);
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint64_Add);
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint64_CompareAndSwap);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Macros)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Macros)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint64_Subtract)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ parcAtomicUint64_Subtract(instance, 1);
+
+ uint64_t actual = parcAtomicUint64_GetValue(instance);
+
+ assertTrue(actual == 6, "Expected 6, actual %" PRIu64, actual);
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint64_Add)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ parcAtomicUint64_Add(instance, 1);
+
+ uint64_t actual = parcAtomicUint64_GetValue(instance);
+
+ assertTrue(actual == 8, "Expected 8, actual %" PRIu64, actual);
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint64_CompareAndSwap)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(7);
+
+ bool actual = parcAtomicUint64_CompareAndSwap(instance, 7, 8);
+
+ assertTrue(actual, "Expected parcAtomicUint64_CompareAndSwap to return true");
+ parcAtomicUint64_Release(&instance);
+}
+
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_Subtract_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_Add_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_CompareAndSwap_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_SubtractImpl);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_AddImpl);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint64_CompareAndSwapImpl);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_Subtract_MACRO)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(100000000);
+
+ while (parcAtomicUint64_Subtract(instance, 1) > 0) {
+ ;
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_Add_MACRO)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(1);
+
+ while (parcAtomicUint64_Add(instance, 1) < 100000000) {
+ ;
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_CompareAndSwap_MACRO)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(0);
+
+ for (uint64_t i = 0; i < 100000000; i++) {
+ bool actual = parcAtomicUint64_CompareAndSwap(instance, i, i + 1);
+ assertTrue(actual, "Expected parcAtomicUint64_CompareAndSwap to return true");
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_SubtractImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(100000000);
+
+ while (parcAtomicUint64_SubtractImpl(instance, 1) > 0) {
+ ;
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_AddImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(1);
+
+ while (parcAtomicUint64_AddImpl(instance, 1) < 100000000) {
+ ;
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint64_CompareAndSwapImpl)
+{
+ PARCAtomicUint64 *instance = parcAtomicUint64_Create(0);
+
+ for (uint64_t i = 0; i < 100000000; i++) {
+ bool actual = parcAtomicUint64_CompareAndSwapImpl(instance, i, i + 1);
+ assertTrue(actual, "Expected parcAtomicUint64_CompareAndSwapImpl to return true");
+ }
+
+ parcAtomicUint64_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_AtomicUint64);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_AtomicUint8.c b/libparc/parc/concurrent/test/test_parc_AtomicUint8.c
new file mode 100644
index 00000000..5b89d052
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_AtomicUint8.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include "../parc_AtomicUint8.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <inttypes.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_AtomicUint8)
+{
+ // 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);
+ LONGBOW_RUN_TEST_FIXTURE(Macros);
+ LONGBOW_RUN_TEST_FIXTURE(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_AtomicUint8)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_AtomicUint8)
+{
+ 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)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+ assertNotNull(instance, "Expeced non-null result from parcAtomicUint8_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcAtomicUint8_Acquire, instance);
+
+ parcAtomicUint8_Release(&instance);
+ assertNull(instance, "Expected null result from parcAtomicUint8_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint8_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint8_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint8_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint8_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint8_IsValid);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint8_SubtractImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint8_AddImpl);
+ LONGBOW_RUN_TEST_CASE(Global, parcAtomicUint8_CompareAndSwapImpl);
+}
+
+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, parcAtomicUint8_Compare)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+ PARCAtomicUint8 *high = parcAtomicUint8_Create(8);
+ PARCAtomicUint8 *low = parcAtomicUint8_Create(6);
+ PARCAtomicUint8 *equal = parcAtomicUint8_Create(7);
+
+ int actual = parcAtomicUint8_Compare(instance, high);
+ assertTrue(actual < 0, "Expected < 0");
+ actual = parcAtomicUint8_Compare(instance, low);
+ assertTrue(actual > 0, "Expected > 0");
+ actual = parcAtomicUint8_Compare(instance, equal);
+ assertTrue(actual == 0, "Expected == 0");
+
+ parcAtomicUint8_Release(&instance);
+ parcAtomicUint8_Release(&high);
+ parcAtomicUint8_Release(&low);
+ parcAtomicUint8_Release(&equal);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint8_Copy)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+ PARCAtomicUint8 *copy = parcAtomicUint8_Copy(instance);
+
+ assertTrue(parcAtomicUint8_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcAtomicUint8_Release(&instance);
+ parcAtomicUint8_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint8_Equals)
+{
+ PARCAtomicUint8 *x = parcAtomicUint8_Create(7);
+ PARCAtomicUint8 *y = parcAtomicUint8_Create(7);
+ PARCAtomicUint8 *z = parcAtomicUint8_Create(7);
+ PARCAtomicUint8 *u1 = parcAtomicUint8_Create(6);
+
+ parcObjectTesting_AssertEquals(x, y, z, u1, NULL);
+
+ parcAtomicUint8_Release(&x);
+ parcAtomicUint8_Release(&y);
+ parcAtomicUint8_Release(&z);
+ parcAtomicUint8_Release(&u1);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint8_HashCode)
+{
+ PARCAtomicUint8 *x = parcAtomicUint8_Create(7);
+ parcAtomicUint8_HashCode(x);
+ parcAtomicUint8_Release(&x);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint8_IsValid)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+ assertTrue(parcAtomicUint8_IsValid(instance), "Expected parcAtomicUint8_Create to result in a valid instance.");
+
+ parcAtomicUint8_Release(&instance);
+ assertFalse(parcAtomicUint8_IsValid(instance), "Expected parcAtomicUint8_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint8_SubtractImpl)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+
+ parcAtomicUint8_SubtractImpl(instance, 1);
+
+ uint8_t actual = parcAtomicUint8_GetValue(instance);
+
+ assertTrue(actual == 6, "Expected 6, actual %" PRIu8, actual);
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint8_AddImpl)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+
+ parcAtomicUint8_AddImpl(instance, 1);
+
+ uint8_t actual = parcAtomicUint8_GetValue(instance);
+
+ assertTrue(actual == 8, "Expected 8, actual %" PRIu8, actual);
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcAtomicUint8_CompareAndSwapImpl)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+
+ bool actual = parcAtomicUint8_CompareAndSwapImpl(instance, 7, 8);
+
+ assertTrue(actual, "Expected parcAtomicUint8_CompareAndSwapImpl to return true");
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Macros)
+{
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint8_Subtract);
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint8_Add);
+ LONGBOW_RUN_TEST_CASE(Macros, parcAtomicUint8_CompareAndSwap);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Macros)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Macros)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint8_Subtract)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+
+ parcAtomicUint8_Subtract(instance, 1);
+
+ uint8_t actual = parcAtomicUint8_GetValue(instance);
+
+ assertTrue(actual == 6, "Expected 6, actual %" PRIu8, actual);
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint8_Add)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+
+ parcAtomicUint8_Add(instance, 1);
+
+ uint8_t actual = parcAtomicUint8_GetValue(instance);
+
+ assertTrue(actual == 8, "Expected 8, actual %" PRIu8, actual);
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Macros, parcAtomicUint8_CompareAndSwap)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(7);
+
+ bool actual = parcAtomicUint8_CompareAndSwap(instance, 7, 8);
+
+ assertTrue(actual, "Expected parcAtomicUint8_CompareAndSwap to return true");
+ parcAtomicUint8_Release(&instance);
+}
+
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint8_Subtract_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint8_Add_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint8_CompareAndSwap_MACRO);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint8_SubtractImpl);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint8_AddImpl);
+ LONGBOW_RUN_TEST_CASE(Performance, parcAtomicUint8_CompareAndSwapImpl);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Performance)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Performance)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint8_Subtract_MACRO)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(255);
+
+ while (parcAtomicUint8_Subtract(instance, 1) > 0) {
+ ;
+ }
+
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint8_Add_MACRO)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(1);
+
+ while (parcAtomicUint8_Add(instance, 1) < 255) {
+ ;
+ }
+
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint8_CompareAndSwap_MACRO)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(0);
+
+ for (uint8_t i = 0; i < 255; i++) {
+ bool actual = parcAtomicUint8_CompareAndSwap(instance, i, i + 1);
+ assertTrue(actual, "Expected parcAtomicUint8_CompareAndSwap to return true");
+ }
+
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint8_SubtractImpl)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(255);
+
+ while (parcAtomicUint8_SubtractImpl(instance, 1) > 0) {
+ ;
+ }
+
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint8_AddImpl)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(1);
+
+ while (parcAtomicUint8_AddImpl(instance, 1) < 255) {
+ ;
+ }
+
+ parcAtomicUint8_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Performance, parcAtomicUint8_CompareAndSwapImpl)
+{
+ PARCAtomicUint8 *instance = parcAtomicUint8_Create(0);
+
+ for (uint8_t i = 0; i < 255; i++) {
+ bool actual = parcAtomicUint8_CompareAndSwapImpl(instance, i, i + 1);
+ assertTrue(actual, "Expected parcAtomicUint8_CompareAndSwapImpl to return true");
+ }
+
+ parcAtomicUint8_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_AtomicUint8);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_FutureTask.c b/libparc/parc/concurrent/test/test_parc_FutureTask.c
new file mode 100644
index 00000000..c30d2cae
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_FutureTask.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 "../parc_FutureTask.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(parc_FutureTask)
+{
+ // 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(parc_FutureTask)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_FutureTask)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease_PARCObject);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ int initialAllocations = longBowTestCase_GetInt(testCase, "initialAllocations");
+
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static void *
+_function(PARCFutureTask *task, void *parameter)
+{
+ return parameter;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCFutureTask *instance = parcFutureTask_Create(_function, _function);
+ assertNotNull(instance, "Expected non-null result from parcFutureTask_Create(_function, _function);");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcFutureTask_Acquire, instance);
+
+ parcFutureTask_Release(&instance);
+ assertNull(instance, "Expected null result from parcFutureTask_Release();");
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease_PARCObject)
+{
+ PARCBuffer *object = parcBuffer_Allocate(10);
+
+ PARCFutureTask *instance = parcFutureTask_Create(_function, object);
+ parcBuffer_Release(&object);
+
+ assertNotNull(instance, "Expected non-null result from parcFutureTask_Create(_function, object);");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcFutureTask_Acquire, instance);
+
+ parcFutureTask_Release(&instance);
+ assertNull(instance, "Expected null result from parcFutureTask_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcFutureTask_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, parcFutureTask_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, parcFutureTask_Display);
+ LONGBOW_RUN_TEST_CASE(Object, parcFutureTask_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcFutureTask_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcFutureTask_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcFutureTask_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcFutureTask_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Object)
+{
+ longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Object)
+{
+ int initialAllocations = longBowTestCase_GetInt(testCase, "initialAllocations");
+
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, parcFutureTask_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Object, parcFutureTask_Copy)
+{
+ PARCFutureTask *instance = parcFutureTask_Create(_function, _function);
+ PARCFutureTask *copy = parcFutureTask_Copy(instance);
+ assertTrue(parcFutureTask_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcFutureTask_Release(&instance);
+ parcFutureTask_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Object, parcFutureTask_Display)
+{
+ PARCFutureTask *instance = parcFutureTask_Create(_function, _function);
+ parcFutureTask_Display(instance, 0);
+ parcFutureTask_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcFutureTask_Equals)
+{
+ PARCFutureTask *x = parcFutureTask_Create(_function, _function);
+ PARCFutureTask *y = parcFutureTask_Create(_function, _function);
+ PARCFutureTask *z = parcFutureTask_Create(_function, _function);
+ PARCFutureTask *u1 = parcFutureTask_Create(_function, NULL);
+
+ parcObjectTesting_AssertEquals(x, y, z, u1, NULL);
+
+ parcFutureTask_Release(&x);
+ parcFutureTask_Release(&y);
+ parcFutureTask_Release(&z);
+ parcFutureTask_Release(&u1);
+}
+
+LONGBOW_TEST_CASE(Object, parcFutureTask_HashCode)
+{
+ PARCFutureTask *x = parcFutureTask_Create(_function, _function);
+ PARCFutureTask *y = parcFutureTask_Create(_function, _function);
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcFutureTask_Release(&x);
+ parcFutureTask_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Object, parcFutureTask_IsValid)
+{
+ PARCFutureTask *instance = parcFutureTask_Create(_function, _function);
+ assertTrue(parcFutureTask_IsValid(instance), "Expected parcFutureTask_Create to result in a valid instance.");
+
+ parcFutureTask_Release(&instance);
+ assertFalse(parcFutureTask_IsValid(instance), "Expected parcFutureTask_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcFutureTask_ToJSON)
+{
+ PARCFutureTask *instance = parcFutureTask_Create(_function, _function);
+
+ PARCJSON *json = parcFutureTask_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcFutureTask_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcFutureTask_ToString)
+{
+ PARCFutureTask *instance = parcFutureTask_Create(_function, _function);
+
+ char *string = parcFutureTask_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcFutureTask_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcFutureTask_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, parcFutureTask_Cancel);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcFutureTask_Get);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcFutureTask_IsCancelled);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcFutureTask_IsDone);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcFutureTask_Run);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcFutureTask_RunAndReset);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ int initialAllocations = longBowTestCase_GetInt(testCase, "initialAllocations");
+
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Specialization, parcFutureTask_Cancel)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ bool parcFutureTask_Cancel(PARCFutureTask *task, bool mayInterruptIfRunning);
+
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcFutureTask_Get)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCFutureTaskResult result = parcFutureTask_Get(task, PARCTimeout_Immediate);
+
+ assertTrue(parcExecution_Is(result.execution, PARCExecution_Timeout), "Expected Timeout, actual %s",
+ parcExecution_GetMessage(result.execution));
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcFutureTask_IsCancelled)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ bool actual = parcFutureTask_IsCancelled(task);
+ assertFalse(actual, "Expected true.");
+
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcFutureTask_IsDone)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ bool actual = parcFutureTask_IsDone(task);
+
+ assertFalse(actual, "Expected false.");
+
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcFutureTask_Run)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ parcFutureTask_Run(task);
+
+ PARCFutureTaskResult actual = parcFutureTask_Get(task, PARCTimeout_Immediate);
+
+ assertTrue(parcFutureTask_IsDone(task), "Expected parcFutureTask_IsDone to be true.");
+ assertTrue(parcExecution_Is(actual.execution, PARCExecution_OK),
+ "Expected OK, actual %s", parcExecution_GetMessage(actual.execution));
+ assertTrue(actual.value == _function, "Expected actual to point to _function");
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcFutureTask_RunAndReset)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ bool actual = parcFutureTask_RunAndReset(task);
+
+ assertTrue(actual, "Expectd parcFutureTask_RunAndReset to return true.");
+ assertFalse(parcFutureTask_IsDone(task), "Expected parcFutureTask_IsDone to be false");
+ parcFutureTask_Release(&task);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_FutureTask);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_Lock.c b/libparc/parc/concurrent/test/test_parc_Lock.c
new file mode 100644
index 00000000..731df04a
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_Lock.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_Lock.c"
+
+#include <stdio.h>
+
+#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(parc_Lock)
+{
+ // 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);
+ LONGBOW_RUN_TEST_FIXTURE(Locking);
+ LONGBOW_RUN_TEST_FIXTURE(WaitNotify);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Lock)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Lock)
+{
+ 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)
+{
+ PARCLock *instance = parcLock_Create();
+ assertNotNull(instance, "Expected non-null result from parcLock_Create().");
+
+ parcObjectTesting_AssertAcquire(instance);
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcLock_Acquire, instance);
+
+ parcLock_Release(&instance);
+ assertNull(instance, "Expected null result from parcLock_Release().");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLock_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcLock_IsValid);
+ LONGBOW_RUN_TEST_CASE(Global, parcLock_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, parcLock_Display)
+{
+ PARCLock *lock = parcLock_Create();
+ parcLock_Display(lock, 0);
+ parcLock_Release(&lock);
+}
+
+LONGBOW_TEST_CASE(Global, parcLock_IsValid)
+{
+ PARCLock *instance = parcLock_Create();
+ assertTrue(parcLock_IsValid(instance), "Expected parcLock_Create to result in a valid instance.");
+
+ parcLock_Release(&instance);
+ assertFalse(parcLock_IsValid(instance), "Expected parcLock_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcLock_ToString)
+{
+ PARCLock *instance = parcLock_Create();
+
+ char *string = parcLock_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcLock_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcLock_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Locking)
+{
+ LONGBOW_RUN_TEST_CASE(Locking, parcLock_TryLock_Unlock);
+ LONGBOW_RUN_TEST_CASE(Locking, parcLock_TryLock_AlreadyLocked);
+ LONGBOW_RUN_TEST_CASE(Locking, parcLock_Lock_Unlock);
+ LONGBOW_RUN_TEST_CASE(Locking, parcLock_Lock_AlreadyLocked);
+ LONGBOW_RUN_TEST_CASE(Locking, parcLock_Lock_AlreadyLocked);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Locking)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Locking)
+{
+ 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;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Locking, parcLock_TryLock_Unlock)
+{
+ PARCLock *lock = parcLock_Create();
+
+ bool actual = parcLock_TryLock(lock);
+
+ assertTrue(actual, "Expected parcObject_TryLock to succeed.");
+
+ actual = parcLock_IsLocked(lock);
+ assertTrue(actual, "Expected parcObject_IsLocked to be true.");
+
+ actual = parcLock_Unlock(lock);
+ assertTrue(actual, "Expected parcObject_Unlock to succeed.");
+
+ actual = parcLock_IsLocked(lock);
+ assertTrue(actual, "Expected parcObject_IsLocked to be false.");
+
+ parcLock_Release((PARCLock **) &lock);
+}
+
+LONGBOW_TEST_CASE(Locking, parcLock_Lock_Unlock)
+{
+ PARCLock *lock = parcLock_Create();
+
+ bool actual = parcLock_Lock(lock);
+
+ assertTrue(actual, "Expected parcObject_Lock to succeed.");
+
+ actual = parcLock_IsLocked(lock);
+ assertTrue(actual, "Expected parcObject_IsLocked to be true.");
+
+ actual = parcLock_Unlock(lock);
+ assertTrue(actual, "Expected parcObject_Unlock to succeed.");
+
+ actual = parcLock_IsLocked(lock);
+ assertTrue(actual, "Expected parcObject_IsLocked to be false.");
+
+ parcLock_Release((PARCLock **) &lock);
+}
+
+LONGBOW_TEST_CASE(Locking, parcLock_TryLock_AlreadyLocked)
+{
+ PARCLock *lock = parcLock_Create();
+
+ bool actual = parcLock_TryLock(lock);
+
+ assertTrue(actual, "Expected parcObject_TryLock to succeed.");
+
+ actual = parcLock_TryLock(lock);
+
+ assertFalse(actual, "Expected parcObject_TryLock to fail when already locked.");
+
+ actual = parcLock_Unlock(lock);
+ assertTrue(actual, "Expected parcObject_Unlock to succeed.");
+
+ parcLock_Release((PARCLock **) &lock);
+}
+
+LONGBOW_TEST_CASE(Locking, parcLock_Lock_AlreadyLocked)
+{
+ PARCLock *lock = parcLock_Create();
+
+ bool actual = parcLock_Lock(lock);
+
+ assertTrue(actual, "Expected parcObject_Lock to succeed.");
+
+ actual = parcLock_Lock(lock);
+
+ assertFalse(actual, "Expected parcObject_Lock to fail when already locked by the same thread.");
+
+ actual = parcLock_Unlock(lock);
+ assertTrue(actual, "Expected parcObject_Unlock to succeed.");
+
+ parcLock_Release((PARCLock **) &lock);
+}
+
+LONGBOW_TEST_FIXTURE(WaitNotify)
+{
+ LONGBOW_RUN_TEST_CASE(WaitNotify, parcLock_WaitNotify);
+ LONGBOW_RUN_TEST_CASE(WaitNotify, parcLock_WaitNotify2);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(WaitNotify)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(WaitNotify)
+{
+ 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;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static int _sharedValue;
+
+static void *
+waiter(void *data)
+{
+ PARCLock *lock = data;
+
+ while (parcLock_TryLock(lock) == false) {
+ ;
+ }
+ parcLock_Wait(lock);
+
+ _sharedValue++;
+ parcLock_Unlock(lock);
+
+ return data;
+}
+
+LONGBOW_TEST_CASE(WaitNotify, parcLock_WaitNotify)
+{
+ PARCLock *lock = parcLock_Create();
+
+ _sharedValue = 0;
+
+ pthread_t thread_A;
+ pthread_t thread_B;
+ pthread_t thread_C;
+ pthread_create(&thread_A, NULL, waiter, lock);
+ pthread_create(&thread_B, NULL, waiter, lock);
+ pthread_create(&thread_C, NULL, waiter, lock);
+
+ while (_sharedValue != 3) {
+ while (parcLock_TryLock(lock) == false) {
+ ;
+ }
+ parcLock_Notify(lock);
+ parcLock_Unlock(lock);
+ }
+
+ pthread_join(thread_A, NULL);
+
+ parcLock_Release((PARCLock **) &lock);
+}
+
+static void *
+decrement(void *data)
+{
+ PARCLock *lock = data;
+
+ while (parcLock_TryLock(lock) == false) {
+ assertTrue(write(1, ".", 1) == 1, "Write failed.");
+ }
+ while (_sharedValue < 12) {
+ parcLock_Wait(lock);
+ _sharedValue--;
+ }
+ parcLock_Unlock(lock);
+
+ return data;
+}
+
+LONGBOW_TEST_CASE(WaitNotify, parcLock_WaitNotify2)
+{
+ PARCLock *lock = parcLock_Create();
+
+ _sharedValue = 0;
+
+ pthread_t thread_A;
+ pthread_create(&thread_A, NULL, decrement, lock);
+
+ _sharedValue = 2;
+ while (parcLock_TryLock(lock) == false) {
+ assertTrue(write(1, ".", 1) == 1, "Write failed.");
+ }
+ while (_sharedValue <= 12) {
+ printf("%d\n", _sharedValue);
+ parcLock_Notify(lock);
+ _sharedValue += 2;
+ }
+ parcLock_Unlock(lock);
+
+ parcLock_Notify(lock);
+ pthread_join(thread_A, NULL);
+
+ parcLock_Release((PARCLock **) &lock);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Lock);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_Notifier.c b/libparc/parc/concurrent/test/test_parc_Notifier.c
new file mode 100755
index 00000000..97ce6615
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_Notifier.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 "../parc_Notifier.c"
+
+#include <sys/time.h>
+#include <pthread.h>
+#include <poll.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_Notifier)
+{
+ // 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(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Notifier)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Notifier)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcNotifier_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcNotifier_Create_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcNotifier_PauseEvent_NotPaused);
+ LONGBOW_RUN_TEST_CASE(Global, parcNotifier_PauseEvent_AlreadyPaused);
+ LONGBOW_RUN_TEST_CASE(Global, parcNotifier_StartEvents);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcNotifier_Notify_First);
+ LONGBOW_RUN_TEST_CASE(Global, parcNotifier_Notify_Twice);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcNotifier_ThreadedTest);
+}
+
+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;
+}
+
+// ------
+typedef struct test_data {
+ volatile int barrier;
+ PARCNotifier *notifier;
+
+ unsigned notificationsToSend;
+ unsigned notificationsSent;
+
+ unsigned notificationsToRecieve;
+ unsigned notificationsReceived;
+
+ pthread_t producerThread;
+ pthread_t consumerThread;
+} TestData;
+
+
+void *
+consumer(void *p)
+{
+ TestData *data = (TestData *) p;
+ --data->barrier;
+ while (data->barrier) {
+ ;
+ }
+
+ struct pollfd pfd;
+ pfd.fd = parcNotifier_Socket(data->notifier);
+ pfd.events = POLLIN;
+
+ while (data->notificationsReceived < data->notificationsToRecieve) {
+ if (poll(&pfd, 1, -1)) {
+ data->notificationsReceived++;
+ parcNotifier_PauseEvents(data->notifier);
+ usleep(rand() % 1024 + 1024);
+ printf("skipped = %d\n", data->notifier->skippedNotify);
+ parcNotifier_StartEvents(data->notifier);
+ }
+ }
+
+ --data->barrier;
+
+ printf("Consumer exiting: received %d\n", data->notificationsReceived);
+ pthread_exit((void *) NULL);
+}
+
+void *
+producer(void *p)
+{
+ TestData *data = (TestData *) p;
+ --data->barrier;
+ while (data->barrier) {
+ ;
+ }
+
+ while (data->barrier == 0) {
+ if (parcNotifier_Notify(data->notifier)) {
+ }
+ data->notificationsSent++;
+ usleep(rand() % 1024 + 512);
+ }
+
+ printf("Producer exiting: sent %d\n", data->notificationsSent);
+ pthread_exit((void *) NULL);
+}
+
+LONGBOW_TEST_CASE(Global, parcNotifier_Acquire)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcNotifier_Create_Release)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcNotifier_PauseEvent_NotPaused)
+{
+ PARCNotifier *notifier = parcNotifier_Create();
+
+ parcNotifier_PauseEvents(notifier);
+ assertTrue(notifier->paused == 1, "Not paused, got %d expected %d", notifier->paused, 1);
+ assertTrue(notifier->skippedNotify == 0, "Wrong skipped, got %d expected %d", notifier->skippedNotify, 0);
+
+ parcNotifier_Release(&notifier);
+}
+
+LONGBOW_TEST_CASE(Global, parcNotifier_PauseEvent_AlreadyPaused)
+{
+ PARCNotifier *notifier = parcNotifier_Create();
+
+ parcNotifier_PauseEvents(notifier);
+
+ // now pause again
+ parcNotifier_PauseEvents(notifier);
+
+ assertTrue(notifier->paused == 1, "Not paused, got %d expected %d", notifier->paused, 1);
+ assertTrue(notifier->skippedNotify == 0, "Wrong skipped, got %d expected %d", notifier->skippedNotify, 0);
+
+ parcNotifier_Release(&notifier);
+}
+
+
+LONGBOW_TEST_CASE(Global, parcNotifier_ThreadedTest)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ data->notifier = parcNotifier_Create();
+ data->notificationsToSend = 10;
+ data->notificationsToRecieve = data->notificationsToSend;
+ data->notificationsSent = 0;
+ data->notificationsReceived = 0;
+ data->barrier = 2;
+
+ pthread_create(&data->consumerThread, NULL, consumer, data);
+ pthread_create(&data->producerThread, NULL, producer, data);
+
+ // wait for them to exit
+ pthread_join(data->producerThread, NULL);
+ pthread_join(data->consumerThread, NULL);
+
+ assertTrue(data->notificationsReceived >= data->notificationsToRecieve,
+ "Did not write all items got %u expected %u\n",
+ data->notificationsReceived,
+ data->notificationsToRecieve);
+
+ parcNotifier_Release(&data->notifier);
+ parcMemory_Deallocate((void **) &data);
+}
+
+LONGBOW_TEST_CASE(Global, parcNotifier_StartEvents)
+{
+ testUnimplemented("unimplemented");
+}
+
+LONGBOW_TEST_CASE(Global, parcNotifier_Notify_First)
+{
+ PARCNotifier *notifier = parcNotifier_Create();
+
+ bool success = parcNotifier_Notify(notifier);
+ assertTrue(success, "Did not succeed on first notify");
+ assertTrue(notifier->paused == 1, "Not paused, got %d expected %d", notifier->paused, 1);
+ assertTrue(notifier->skippedNotify == 0, "Wrong skipped, got %d expected %d", notifier->skippedNotify, 0);
+
+ parcNotifier_Release(&notifier);
+}
+
+
+LONGBOW_TEST_CASE(Global, parcNotifier_Notify_Twice)
+{
+ PARCNotifier *notifier = parcNotifier_Create();
+
+ parcNotifier_Notify(notifier);
+
+ bool success = parcNotifier_Notify(notifier);
+ assertFalse(success, "Should have failed on second notify");
+ assertTrue(notifier->paused == 1, "Not paused, got %d expected %d", notifier->paused, 1);
+ assertTrue(notifier->skippedNotify == 1, "Wrong skipped, got %d expected %d", notifier->skippedNotify, 1);
+
+ parcNotifier_Release(&notifier);
+}
+
+// ===============================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+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;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Notifier);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_RingBuffer_1x1.c b/libparc/parc/concurrent/test/test_parc_RingBuffer_1x1.c
new file mode 100755
index 00000000..a977dfbc
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_RingBuffer_1x1.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_RingBuffer_1x1.c"
+
+#include <sys/time.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_RingBuffer_1x1)
+{
+ // 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(parc_RingBuffer_1x1)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_RingBuffer_1x1)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcRingBuffer1x1_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcRingBuffer1x1_Create_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcRingBuffer1x1_Create_NonPower2);
+ LONGBOW_RUN_TEST_CASE(Global, parcRingBuffer1x1_Get_Put);
+ LONGBOW_RUN_TEST_CASE(Global, parcRingBuffer1x1_Remaining_Empty);
+ LONGBOW_RUN_TEST_CASE(Global, parcRingBuffer1x1_Remaining_Half);
+ LONGBOW_RUN_TEST_CASE(Global, parcRingBuffer1x1_Remaining_Full);
+ LONGBOW_RUN_TEST_CASE(Global, parcRingBuffer1x1_Put_ToCapacity);
+}
+
+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;
+}
+
+// ------
+typedef struct test_ringbuffer {
+ unsigned itemsToWrite;
+ volatile unsigned itemsWritten;
+ volatile unsigned itemsRead;
+ volatile bool blocked;
+
+ PARCRingBuffer1x1 *producerBuffer;
+ PARCRingBuffer1x1 *consumerBuffer;
+
+ pthread_t producerThread;
+ pthread_t consumerThread;
+} TestRingBuffer;
+
+
+void *
+consumer(void *p)
+{
+ TestRingBuffer *trb = (TestRingBuffer *) p;
+
+ while (trb->blocked) {
+ // nothing to do.
+ }
+
+ while (trb->itemsRead < trb->itemsToWrite) {
+ uint32_t *data;
+ bool success = parcRingBuffer1x1_Get(trb->consumerBuffer, (void **) &data);
+ if (success) {
+ assertTrue(*data == trb->itemsRead, "Got out of order item %u expected %u\n", *data, trb->itemsRead);
+ parcMemory_Deallocate((void **) &data);
+ trb->itemsRead++;
+ }
+ }
+
+ pthread_exit((void *) NULL);
+}
+
+void *
+producer(void *p)
+{
+ TestRingBuffer *trb = (TestRingBuffer *) p;
+
+ while (trb->blocked) {
+ // nothing to do
+ }
+
+ while (trb->itemsWritten < trb->itemsToWrite) {
+ uint32_t *data = parcMemory_Allocate(sizeof(uint32_t));
+ assertNotNull(data, "parcMemory_Allocate(%zu) returned NULL", sizeof(uint32_t));
+ *data = trb->itemsWritten;
+
+ bool success = false;
+ do {
+ success = parcRingBuffer1x1_Put(trb->producerBuffer, data);
+ } while (!success);
+ trb->itemsWritten++;
+ }
+
+ pthread_exit((void *) NULL);
+}
+
+LONGBOW_TEST_CASE(Global, parcRingBuffer1x1_Acquire)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcRingBuffer1x1_Create_NonPower2, .event = &LongBowAssertEvent)
+{
+ // this will assert because the number of elements is not a power of 2
+ parcRingBuffer1x1_Create(3, NULL);
+}
+
+LONGBOW_TEST_CASE(Global, parcRingBuffer1x1_Create_Release)
+{
+ PARCRingBuffer1x1 *ring = parcRingBuffer1x1_Create(1024, NULL);
+ parcRingBuffer1x1_Release(&ring);
+ assertTrue(parcMemory_Outstanding() == 0, "Non-zero memory balance: %u", parcMemory_Outstanding());
+
+ printf("ring buffer entry size: %zu\n", sizeof(PARCRingBuffer1x1));
+}
+
+LONGBOW_TEST_CASE(Global, parcRingBuffer1x1_Get_Put)
+{
+ TestRingBuffer *trb = parcMemory_AllocateAndClear(sizeof(TestRingBuffer));
+ assertNotNull(trb, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestRingBuffer));
+ trb->producerBuffer = parcRingBuffer1x1_Create(128, NULL);
+ trb->consumerBuffer = parcRingBuffer1x1_Acquire(trb->producerBuffer);
+
+ trb->itemsToWrite = 100000;
+ trb->blocked = true;
+
+ pthread_create(&trb->consumerThread, NULL, consumer, trb);
+ pthread_create(&trb->producerThread, NULL, producer, trb);
+
+ struct timeval t0, t1;
+
+ gettimeofday(&t0, NULL);
+ trb->blocked = false;
+
+ // wait for them to exit
+ pthread_join(trb->producerThread, NULL);
+ pthread_join(trb->consumerThread, NULL);
+ gettimeofday(&t1, NULL);
+
+ timersub(&t1, &t0, &t1);
+
+ assertTrue(trb->itemsWritten == trb->itemsToWrite,
+ "Did not write all items got %u expected %u\n",
+ trb->itemsWritten,
+ trb->itemsToWrite);
+
+ assertTrue(trb->itemsRead == trb->itemsToWrite,
+ "Did not read all items got %u expected %u\n",
+ trb->itemsRead,
+ trb->itemsToWrite);
+
+ double sec = t1.tv_sec + t1.tv_usec * 1E-6;
+
+ printf("Passed %u items in %.6f seconds, %.2f items/sec\n",
+ trb->itemsWritten,
+ sec,
+ trb->itemsWritten / sec);
+
+ parcRingBuffer1x1_Release(&trb->consumerBuffer);
+ parcRingBuffer1x1_Release(&trb->producerBuffer);
+ parcMemory_Deallocate((void **) &trb);
+}
+
+LONGBOW_TEST_CASE(Global, parcRingBuffer1x1_Remaining_Empty)
+{
+ uint32_t capacity = 128;
+ PARCRingBuffer1x1 *ring = parcRingBuffer1x1_Create(capacity, NULL);
+ uint32_t remaining = parcRingBuffer1x1_Remaining(ring);
+ parcRingBuffer1x1_Release(&ring);
+
+ // -1 because the ring buffer is always -1
+ assertTrue(remaining == capacity - 1, "Got wrong remaining, got %u expecting %u\n", remaining, capacity);
+}
+
+LONGBOW_TEST_CASE(Global, parcRingBuffer1x1_Remaining_Half)
+{
+ uint32_t capacity = 128;
+ PARCRingBuffer1x1 *ring = parcRingBuffer1x1_Create(capacity, NULL);
+ for (int i = 0; i < capacity / 2; i++) {
+ parcRingBuffer1x1_Put(ring, &i);
+ }
+
+ uint32_t remaining = parcRingBuffer1x1_Remaining(ring);
+ parcRingBuffer1x1_Release(&ring);
+
+ // -1 because the ring buffer is always -1
+ assertTrue(remaining == capacity / 2 - 1, "Got wrong remaining, got %u expecting %u\n", remaining, capacity / 2 - 1);
+}
+
+LONGBOW_TEST_CASE(Global, parcRingBuffer1x1_Remaining_Full)
+{
+ uint32_t capacity = 128;
+ PARCRingBuffer1x1 *ring = parcRingBuffer1x1_Create(capacity, NULL);
+ for (int i = 0; i < capacity - 1; i++) {
+ parcRingBuffer1x1_Put(ring, &i);
+ }
+
+ uint32_t remaining = parcRingBuffer1x1_Remaining(ring);
+ parcRingBuffer1x1_Release(&ring);
+
+ assertTrue(remaining == 0, "Got wrong remaining, got %u expecting %u\n", remaining, 0);
+}
+
+LONGBOW_TEST_CASE(Global, parcRingBuffer1x1_Put_ToCapacity)
+{
+ uint32_t capacity = 128;
+ PARCRingBuffer1x1 *ring = parcRingBuffer1x1_Create(capacity, NULL);
+ for (int i = 0; i < capacity - 1; i++) {
+ parcRingBuffer1x1_Put(ring, &i);
+ }
+
+ // this next put should fail
+ bool success = parcRingBuffer1x1_Put(ring, &capacity);
+
+ parcRingBuffer1x1_Release(&ring);
+
+ assertFalse(success, "Should have failed on final put because data structure is full\n");
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _create);
+ LONGBOW_RUN_TEST_CASE(Local, _destroy);
+ LONGBOW_RUN_TEST_CASE(Local, _isPowerOfTwo);
+}
+
+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, _create)
+{
+ testUnimplemented("");
+}
+
+static void
+_testDestoryer(void **ptr)
+{
+ parcBuffer_Release((PARCBuffer **) ptr);
+}
+
+LONGBOW_TEST_CASE(Local, _destroy)
+{
+ // put something in the ring and don't remove it. Make sure the destroyer catches it.
+
+ uint32_t capacity = 128;
+ PARCRingBuffer1x1 *ring = parcRingBuffer1x1_Create(capacity, _testDestoryer);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(5);
+ parcRingBuffer1x1_Put(ring, buffer);
+
+ parcRingBuffer1x1_Release(&ring);
+ assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance, expected 0 got %u", parcMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Local, _isPowerOfTwo)
+{
+ struct test_struct {
+ uint32_t value;
+ bool isPow2;
+ } test_vector[] = { { 0, false }, { 1, true }, { 2, true }, { 15, false }, { 16, true }, { 32, true }, { UINT32_MAX, true } };
+
+ for (int i = 0; test_vector[i].value != UINT32_MAX; i++) {
+ bool test = _isPowerOfTwo(test_vector[i].value);
+ assertTrue(test == test_vector[i].isPow2, "Got wrong result for value %u, got %d expected %d\n", test_vector[i].value, test, test_vector[i].isPow2);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_RingBuffer_1x1);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_RingBuffer_NxM.c b/libparc/parc/concurrent/test/test_parc_RingBuffer_NxM.c
new file mode 100755
index 00000000..974da053
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_RingBuffer_NxM.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 "../parc_RingBuffer_NxM.c"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_RingBuffer_NxM)
+{
+ // 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(parc_RingBuffer_NxM)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_RingBuffer_NxM)
+{
+ 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("Tests leak memory by %d allocations\n", outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _destroy);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static void
+_testDestoryer(void **ptr)
+{
+ parcBuffer_Release((PARCBuffer **) ptr);
+}
+
+LONGBOW_TEST_CASE(Local, _destroy)
+{
+ // put something in the ring and don't remove it. Make sure the destroyer catches it.
+
+ uint32_t capacity = 128;
+ PARCRingBufferNxM *ring = parcRingBufferNxM_Create(capacity, _testDestoryer);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(5);
+ parcRingBufferNxM_Put(ring, buffer);
+
+ parcRingBufferNxM_Release(&ring);
+ assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance, expected 0 got %u", parcMemory_Outstanding());
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_RingBuffer_NxM);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_ScheduledTask.c b/libparc/parc/concurrent/test/test_parc_ScheduledTask.c
new file mode 100644
index 00000000..3655be93
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_ScheduledTask.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ */
+#include "../parc_ScheduledTask.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(parc_ScheduledTask)
+{
+ // 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(parc_ScheduledTask)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_ScheduledTask)
+{
+ 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;
+}
+
+void *
+_function(PARCFutureTask *task, void *parameter)
+{
+ return parameter;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCScheduledTask *instance = parcScheduledTask_Create(task, 0);
+ assertNotNull(instance, "Expected non-null result from parcScheduledTask_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcScheduledTask_Acquire, instance);
+
+ parcScheduledTask_Release(&instance);
+ assertNull(instance, "Expected null result from parcScheduledTask_Release();");
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledTask_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledTask_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledTask_Display);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledTask_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledTask_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledTask_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledTask_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledTask_ToString);
+}
+
+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, parcScheduledTask_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledTask_Copy)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCScheduledTask *instance = parcScheduledTask_Create(task, 0);
+ PARCScheduledTask *copy = parcScheduledTask_Copy(instance);
+ assertTrue(parcScheduledTask_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcScheduledTask_Release(&instance);
+ parcScheduledTask_Release(&copy);
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledTask_Display)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCScheduledTask *instance = parcScheduledTask_Create(task, 0);
+ parcScheduledTask_Display(instance, 0);
+ parcScheduledTask_Release(&instance);
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledTask_Equals)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCScheduledTask *x = parcScheduledTask_Create(task, 0);
+ PARCScheduledTask *y = parcScheduledTask_Create(task, 0);
+ PARCScheduledTask *z = parcScheduledTask_Create(task, 0);
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcScheduledTask_Release(&x);
+ parcScheduledTask_Release(&y);
+ parcScheduledTask_Release(&z);
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledTask_HashCode)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCScheduledTask *x = parcScheduledTask_Create(task, 0);
+ PARCScheduledTask *y = parcScheduledTask_Create(task, 0);
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcScheduledTask_Release(&x);
+ parcScheduledTask_Release(&y);
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledTask_IsValid)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCScheduledTask *instance = parcScheduledTask_Create(task, 0);
+ assertTrue(parcScheduledTask_IsValid(instance), "Expected parcScheduledTask_Create to result in a valid instance.");
+
+ parcScheduledTask_Release(&instance);
+ assertFalse(parcScheduledTask_IsValid(instance), "Expected parcScheduledTask_Release to result in an invalid instance.");
+
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledTask_ToJSON)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCScheduledTask *instance = parcScheduledTask_Create(task, 0);
+
+ PARCJSON *json = parcScheduledTask_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcScheduledTask_Release(&instance);
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledTask_ToString)
+{
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ PARCScheduledTask *instance = parcScheduledTask_Create(task, 0);
+
+ char *string = parcScheduledTask_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcScheduledTask_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcScheduledTask_Release(&instance);
+ parcFutureTask_Release(&task);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+}
+
+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;
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_ScheduledTask);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libparc/parc/concurrent/test/test_parc_ScheduledThreadPool.c b/libparc/parc/concurrent/test/test_parc_ScheduledThreadPool.c
new file mode 100644
index 00000000..f466d72a
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_ScheduledThreadPool.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 "../parc_ScheduledThreadPool.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(parc_ScheduledThreadPool)
+{
+ // 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(parc_ScheduledThreadPool)
+{
+ 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_ScheduledThreadPool)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ longBowTestCase_SetInt(testCase, "initalAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ int initialAllocations = longBowTestCase_GetInt(testCase, "initalAllocations");
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCScheduledThreadPool *instance = parcScheduledThreadPool_Create(3);
+ assertNotNull(instance, "Expected non-null result from parcScheduledThreadPool_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcScheduledThreadPool_Acquire, instance);
+ parcScheduledThreadPool_ShutdownNow(instance);
+
+ assertTrue(parcObject_GetReferenceCount(instance) == 1, "Expected 1 reference count. Actual %llu", parcObject_GetReferenceCount(instance));
+
+ parcScheduledThreadPool_Release(&instance);
+ assertNull(instance, "Expected null result from parcScheduledThreadPool_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledThreadPool_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledThreadPool_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledThreadPool_Display);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledThreadPool_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledThreadPool_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledThreadPool_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledThreadPool_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcScheduledThreadPool_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Object)
+{
+ longBowTestCase_SetInt(testCase, "initalAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Object)
+{
+ int initialAllocations = longBowTestCase_GetInt(testCase, "initalAllocations");
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledThreadPool_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledThreadPool_Copy)
+{
+ PARCScheduledThreadPool *instance = parcScheduledThreadPool_Create(3);
+ PARCScheduledThreadPool *copy = parcScheduledThreadPool_Copy(instance);
+ assertTrue(parcScheduledThreadPool_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcScheduledThreadPool_ShutdownNow(instance);
+ parcScheduledThreadPool_ShutdownNow(copy);
+
+ parcScheduledThreadPool_Release(&instance);
+ parcScheduledThreadPool_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledThreadPool_Display)
+{
+ PARCScheduledThreadPool *instance = parcScheduledThreadPool_Create(2);
+ parcScheduledThreadPool_Display(instance, 0);
+ parcScheduledThreadPool_ShutdownNow(instance);
+ parcScheduledThreadPool_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledThreadPool_Equals)
+{
+ PARCScheduledThreadPool *x = parcScheduledThreadPool_Create(2);
+ PARCScheduledThreadPool *y = parcScheduledThreadPool_Create(2);
+ PARCScheduledThreadPool *z = parcScheduledThreadPool_Create(2);
+ PARCScheduledThreadPool *u1 = parcScheduledThreadPool_Create(3);
+
+ parcObjectTesting_AssertEquals(x, y, z, u1, NULL);
+
+ parcScheduledThreadPool_ShutdownNow(x);
+ parcScheduledThreadPool_ShutdownNow(y);
+ parcScheduledThreadPool_ShutdownNow(z);
+ parcScheduledThreadPool_ShutdownNow(u1);
+
+ parcScheduledThreadPool_Release(&x);
+ parcScheduledThreadPool_Release(&y);
+ parcScheduledThreadPool_Release(&z);
+ parcScheduledThreadPool_Release(&u1);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledThreadPool_HashCode)
+{
+ PARCScheduledThreadPool *x = parcScheduledThreadPool_Create(2);
+ PARCScheduledThreadPool *y = parcScheduledThreadPool_Create(2);
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcScheduledThreadPool_ShutdownNow(x);
+ parcScheduledThreadPool_ShutdownNow(y);
+
+ parcScheduledThreadPool_Release(&x);
+ parcScheduledThreadPool_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledThreadPool_IsValid)
+{
+ PARCScheduledThreadPool *instance = parcScheduledThreadPool_Create(2);
+ assertTrue(parcScheduledThreadPool_IsValid(instance), "Expected parcScheduledThreadPool_Create to result in a valid instance.");
+
+ parcScheduledThreadPool_ShutdownNow(instance);
+
+ parcScheduledThreadPool_Release(&instance);
+ assertFalse(parcScheduledThreadPool_IsValid(instance), "Expected parcScheduledThreadPool_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledThreadPool_ToJSON)
+{
+ PARCScheduledThreadPool *instance = parcScheduledThreadPool_Create(2);
+
+ PARCJSON *json = parcScheduledThreadPool_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcScheduledThreadPool_ShutdownNow(instance);
+ parcScheduledThreadPool_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcScheduledThreadPool_ToString)
+{
+ PARCScheduledThreadPool *instance = parcScheduledThreadPool_Create(2);
+
+ char *string = parcScheduledThreadPool_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcScheduledThreadPool_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcScheduledThreadPool_ShutdownNow(instance);
+ parcScheduledThreadPool_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, OneJob);
+ LONGBOW_RUN_TEST_CASE(Specialization, Idle);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcScheduledThreadPool_Schedule);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ longBowTestCase_SetInt(testCase, "initalAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ int initialAllocations = longBowTestCase_GetInt(testCase, "initalAllocations");
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Specialization, Idle)
+{
+ PARCScheduledThreadPool *pool = parcScheduledThreadPool_Create(3);
+
+ sleep(2);
+
+ parcScheduledThreadPool_ShutdownNow(pool);
+
+ parcScheduledThreadPool_Release(&pool);
+}
+
+static void *
+_function(PARCFutureTask *task, void *parameter)
+{
+ printf("Hello World\n");
+ return parameter;
+}
+
+LONGBOW_TEST_CASE(Specialization, OneJob)
+{
+ PARCScheduledThreadPool *pool = parcScheduledThreadPool_Create(3);
+
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ parcScheduledThreadPool_Schedule(pool, task, parcTimeout_MilliSeconds(2000));
+ printf("references %lld\n", parcObject_GetReferenceCount(task));
+ parcFutureTask_Release(&task);
+
+ sleep(5);
+
+ parcScheduledThreadPool_ShutdownNow(pool);
+
+ parcScheduledThreadPool_Release(&pool);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcScheduledThreadPool_Schedule)
+{
+ PARCScheduledThreadPool *pool = parcScheduledThreadPool_Create(3);
+
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+
+ parcScheduledThreadPool_Schedule(pool, task, parcTimeout_MilliSeconds(2000));
+
+ parcFutureTask_Release(&task);
+
+ parcScheduledThreadPool_Shutdown(pool);
+// parcScheduledThreadPool_AwaitTermination(pool, PARCTimeout_Never);
+
+// uint64_t count = parcScheduledThreadPool_GetCompletedTaskCount(pool);
+// assertTrue(count == 5, "Expected 5, actual %lld", count);
+
+ parcScheduledThreadPool_ShutdownNow(pool);
+
+ parcScheduledThreadPool_Release(&pool);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_ScheduledThreadPool);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/concurrent/test/test_parc_Synchronizer.c b/libparc/parc/concurrent/test/test_parc_Synchronizer.c
new file mode 100755
index 00000000..34d9c711
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_Synchronizer.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 "../parc_Synchronizer.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_Synchronizer)
+{
+ // 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(parc_Synchronizer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Synchronizer)
+{
+ 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)
+{
+ PARCSynchronizer *instance = parcSynchronizer_Create();
+ assertNotNull(instance, "Expeced non-null result from parcSynchronizer_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcSynchronizer_Acquire, instance);
+
+ parcSynchronizer_Release(&instance);
+ assertNull(instance, "Expeced null result from parcSynchronizer_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcSynchronizer_Display);
+ LONGBOW_RUN_TEST_CASE(Global, parcSynchronizer_IsValid);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcSynchronizer_TryLock);
+ LONGBOW_RUN_TEST_CASE(Global, parcSynchronizer_LockUnlock);
+ LONGBOW_RUN_TEST_CASE(Global, parcSynchronizer_TryLock_Fail);
+ LONGBOW_RUN_TEST_CASE(Global, parcSynchronizer_IsLocked);
+}
+
+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, parcSynchronizer_Display)
+{
+ PARCSynchronizer *instance = parcSynchronizer_Create();
+ assertTrue(parcSynchronizer_IsValid(instance), "Expected parcSynchronizer_Create to result in a valid instance.");
+
+ parcSynchronizer_Display(instance, 0);
+ parcSynchronizer_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcSynchronizer_IsValid)
+{
+ PARCSynchronizer *instance = parcSynchronizer_Create();
+ assertTrue(parcSynchronizer_IsValid(instance), "Expected parcSynchronizer_Create to result in a valid instance.");
+
+ parcSynchronizer_Release(&instance);
+ assertFalse(parcSynchronizer_IsValid(instance), "Expected parcSynchronizer_Create to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Global, parcSynchronizer_TryLock)
+{
+ PARCSynchronizer *instance = parcSynchronizer_Create();
+
+ bool actual = parcSynchronizer_TryLock(instance);
+ assertTrue(actual, "Expected parcSynchronizer_TryLock to be successful.");
+
+ parcSynchronizer_Unlock(instance);
+ parcSynchronizer_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcSynchronizer_TryLock_Fail)
+{
+ PARCSynchronizer *instance = parcSynchronizer_Create();
+
+ parcSynchronizer_Lock(instance);
+ bool actual = parcSynchronizer_TryLock(instance);
+ assertFalse(actual, "Expected parcSynchronizer_TryLock to be unsuccessful.");
+
+ parcSynchronizer_Unlock(instance);
+ parcSynchronizer_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcSynchronizer_LockUnlock)
+{
+ PARCSynchronizer *instance = parcSynchronizer_Create();
+
+ parcSynchronizer_Lock(instance);
+ parcSynchronizer_Unlock(instance);
+
+ parcSynchronizer_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Global, parcSynchronizer_IsLocked)
+{
+ PARCSynchronizer *instance = parcSynchronizer_Create();
+ assertFalse(parcSynchronizer_IsLocked(instance), "Expected the synchronizer to be unlocked.");
+
+ parcSynchronizer_Lock(instance);
+ assertTrue(parcSynchronizer_IsLocked(instance), "Expected the synchronizer to be unlocked.");
+
+ parcSynchronizer_Unlock(instance);
+ assertFalse(parcSynchronizer_IsLocked(instance), "Expected the synchronizer to be unlocked.");
+
+ parcSynchronizer_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Synchronizer);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libparc/parc/concurrent/test/test_parc_Thread.c b/libparc/parc/concurrent/test/test_parc_Thread.c
new file mode 100644
index 00000000..22ca31bf
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_Thread.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.
+ */
+
+
+/**
+ */
+#include "../parc_ThreadPool.c"
+
+#include <stdio.h>
+
+#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(parc_Thread)
+{
+ // 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(parc_Thread)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Thread)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding());
+
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ longBowTestCase_Set(testCase, "object", buffer);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ parcBuffer_Release(&buffer);
+
+ uint32_t initialAllocations = (uint32_t) longBowTestCase_Get(testCase, "initialAllocations");
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static void *
+_function(PARCThread *thread, void *parameter)
+{
+ return NULL;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ PARCThread *thread = parcThread_Create(_function, buffer);
+
+ assertNotNull(thread, "Expected non-null result from parcThread_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcThread_Acquire, thread);
+
+ parcThread_Release(&thread);
+ assertNull(thread, "Expected null result from parcThread_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_Display);
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Object)
+{
+ longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding());
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ longBowTestCase_Set(testCase, "object", buffer);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Object)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ parcBuffer_Release(&buffer);
+
+ uint32_t initialAllocations = (uint32_t) longBowTestCase_Get(testCase, "initialAllocations");
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_Compare)
+{
+// testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_Copy)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ PARCThread *instance = parcThread_Create(_function, buffer);
+ PARCThread *copy = parcThread_Copy(instance);
+
+ assertTrue(parcThread_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcThread_Release(&instance);
+ parcThread_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_Display)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ PARCThread *instance = parcThread_Create(_function, buffer);
+ parcThread_Display(instance, 0);
+
+
+ parcThread_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_Equals)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ PARCThread *x = parcThread_Create(_function, buffer);
+ PARCThread *y = parcThread_Create(_function, buffer);
+ PARCThread *z = parcThread_Create(_function, buffer);
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcThread_Release(&x);
+ parcThread_Release(&y);
+ parcThread_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_HashCode)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ PARCThread *x = parcThread_Create(_function, buffer);
+ PARCThread *y = parcThread_Create(_function, buffer);
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcThread_Release(&x);
+ parcThread_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_IsValid)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ PARCThread *instance = parcThread_Create(_function, buffer);
+ assertTrue(parcThread_IsValid(instance), "Expected parcThread_Create to result in a valid instance.");
+
+
+ parcThread_Release(&instance);
+ assertFalse(parcThread_IsValid(instance), "Expected parcThread_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_ToJSON)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ PARCThread *instance = parcThread_Create(_function, buffer);
+
+ PARCJSON *json = parcThread_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+
+ parcThread_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_ToString)
+{
+ PARCBuffer *buffer = longBowTestCase_Get(testCase, "object");
+ PARCThread *instance = parcThread_Create(_function, buffer);
+
+ char *string = parcThread_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcThread_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+
+ parcThread_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ LONGBOW_RUN_TEST_CASE(Object, parcThread_Execute);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ uint32_t initialAllocations = (uint32_t) longBowTestCase_Get(testCase, "initialAllocations");
+ if (!parcMemoryTesting_ExpectedOutstanding(initialAllocations, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, parcThread_Execute)
+{
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Thread);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libparc/parc/concurrent/test/test_parc_ThreadPool.c b/libparc/parc/concurrent/test/test_parc_ThreadPool.c
new file mode 100644
index 00000000..6ed6e4d3
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_ThreadPool.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ */
+#include "../parc_ThreadPool.c"
+
+#include <stdio.h>
+
+#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(parc_ThreadPool)
+{
+ // 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(parc_ThreadPool)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_ThreadPool)
+{
+ 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)
+{
+ PARCThreadPool *pool = parcThreadPool_Create(6);
+ assertNotNull(pool, "Expected non-null result from parcThreadPool_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcThreadPool_Acquire, pool);
+
+ parcThreadPool_ShutdownNow(pool);
+
+ parcThreadPool_Release(&pool);
+ assertNull(pool, "Expected null result from parcThreadPool_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_Display);
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_ToString);
+}
+
+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, parcThreadPool_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Object, parcThreadPool_Copy)
+{
+ PARCThreadPool *instance = parcThreadPool_Create(6);
+ PARCThreadPool *copy = parcThreadPool_Copy(instance);
+ assertTrue(parcThreadPool_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcThreadPool_ShutdownNow(instance);
+ parcThreadPool_ShutdownNow(copy);
+
+ parcThreadPool_Release(&instance);
+ parcThreadPool_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Object, parcThreadPool_Display)
+{
+ PARCThreadPool *instance = parcThreadPool_Create(6);
+ parcThreadPool_Display(instance, 0);
+
+ parcThreadPool_ShutdownNow(instance);
+
+ parcThreadPool_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcThreadPool_Equals)
+{
+ PARCThreadPool *x = parcThreadPool_Create(6);
+ PARCThreadPool *y = parcThreadPool_Create(6);
+ PARCThreadPool *z = parcThreadPool_Create(6);
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcThreadPool_ShutdownNow(x);
+ parcThreadPool_ShutdownNow(y);
+ parcThreadPool_ShutdownNow(z);
+
+ parcThreadPool_Release(&x);
+ parcThreadPool_Release(&y);
+ parcThreadPool_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Object, parcThreadPool_HashCode)
+{
+ PARCThreadPool *x = parcThreadPool_Create(6);
+ PARCThreadPool *y = parcThreadPool_Create(6);
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcThreadPool_ShutdownNow(x);
+ parcThreadPool_ShutdownNow(y);
+
+ parcThreadPool_Release(&x);
+ parcThreadPool_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Object, parcThreadPool_IsValid)
+{
+ PARCThreadPool *instance = parcThreadPool_Create(6);
+ assertTrue(parcThreadPool_IsValid(instance), "Expected parcThreadPool_Create to result in a valid instance.");
+
+ parcThreadPool_ShutdownNow(instance);
+
+ parcThreadPool_Release(&instance);
+ assertFalse(parcThreadPool_IsValid(instance), "Expected parcThreadPool_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcThreadPool_ToJSON)
+{
+ PARCThreadPool *instance = parcThreadPool_Create(6);
+
+ PARCJSON *json = parcThreadPool_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcThreadPool_ShutdownNow(instance);
+
+ parcThreadPool_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcThreadPool_ToString)
+{
+ PARCThreadPool *instance = parcThreadPool_Create(6);
+
+ char *string = parcThreadPool_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcThreadPool_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+
+ parcThreadPool_ShutdownNow(instance);
+
+ parcThreadPool_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ LONGBOW_RUN_TEST_CASE(Object, parcThreadPool_Execute);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+void *
+_function(PARCFutureTask *task, void *parameter)
+{
+ printf("Hello World\n");
+ return parameter;
+}
+
+LONGBOW_TEST_CASE(Object, parcThreadPool_Execute)
+{
+ dprintf(1, "-----\n");
+ PARCThreadPool *pool = parcThreadPool_Create(6);
+
+ PARCFutureTask *task = parcFutureTask_Create(_function, _function);
+ parcThreadPool_Execute(pool, task);
+ parcThreadPool_Execute(pool, task);
+ parcThreadPool_Execute(pool, task);
+ parcThreadPool_Execute(pool, task);
+ parcThreadPool_Execute(pool, task);
+ parcFutureTask_Release(&task);
+
+ parcThreadPool_Shutdown(pool);
+ bool shutdownSuccess = parcThreadPool_AwaitTermination(pool, PARCTimeout_Never);
+
+ assertTrue(shutdownSuccess, "parcThreadPool_AwaitTermination timed-out");
+
+ uint64_t count = parcThreadPool_GetCompletedTaskCount(pool);
+ assertTrue(count == 5, "Expected 5, actual %lld", count);
+
+
+ parcThreadPool_Release(&pool);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_ThreadPool);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libparc/parc/concurrent/test/test_parc_Timer.c b/libparc/parc/concurrent/test/test_parc_Timer.c
new file mode 100644
index 00000000..5bc7ae6c
--- /dev/null
+++ b/libparc/parc/concurrent/test/test_parc_Timer.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ */
+#include "../parc_Timer.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(parc_Timer)
+{
+ // 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(parc_Timer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Timer)
+{
+ 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)
+{
+ PARCTimer *instance = parcTimer_Create();
+ assertNotNull(instance, "Expected non-null result from parcTimer_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcTimer_Acquire, instance);
+
+ parcTimer_Release(&instance);
+ assertNull(instance, "Expected null result from parcTimer_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcTimer_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, parcTimer_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, parcTimer_Display);
+ LONGBOW_RUN_TEST_CASE(Object, parcTimer_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcTimer_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcTimer_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcTimer_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcTimer_ToString);
+}
+
+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, parcTimer_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Object, parcTimer_Copy)
+{
+ PARCTimer *instance = parcTimer_Create();
+ PARCTimer *copy = parcTimer_Copy(instance);
+ assertTrue(parcTimer_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcTimer_Release(&instance);
+ parcTimer_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Object, parcTimer_Display)
+{
+ PARCTimer *instance = parcTimer_Create();
+ parcTimer_Display(instance, 0);
+ parcTimer_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcTimer_Equals)
+{
+ PARCTimer *x = parcTimer_Create();
+ PARCTimer *y = parcTimer_Create();
+ PARCTimer *z = parcTimer_Create();
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcTimer_Release(&x);
+ parcTimer_Release(&y);
+ parcTimer_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Object, parcTimer_HashCode)
+{
+ PARCTimer *x = parcTimer_Create();
+ PARCTimer *y = parcTimer_Create();
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcTimer_Release(&x);
+ parcTimer_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Object, parcTimer_IsValid)
+{
+ PARCTimer *instance = parcTimer_Create();
+ assertTrue(parcTimer_IsValid(instance), "Expected parcTimer_Create to result in a valid instance.");
+
+ parcTimer_Release(&instance);
+ assertFalse(parcTimer_IsValid(instance), "Expected parcTimer_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcTimer_ToJSON)
+{
+ PARCTimer *instance = parcTimer_Create();
+
+ PARCJSON *json = parcTimer_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcTimer_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcTimer_ToString)
+{
+ PARCTimer *instance = parcTimer_Create();
+
+ char *string = parcTimer_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcTimer_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcTimer_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+}
+
+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;
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Timer);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libparc/parc/config.h.in b/libparc/parc/config.h.in
new file mode 100644
index 00000000..868c03ca
--- /dev/null
+++ b/libparc/parc/config.h.in
@@ -0,0 +1,6 @@
+/* CPU Cache line size */
+#define LEVEL1_DCACHE_LINESIZE @LEVEL1_DCACHE_LINESIZE@
+
+#define _GNU_SOURCE
+
+#define HAVE_REALLOC @HAVE_REALLOC@ \ No newline at end of file
diff --git a/libparc/parc/developer/parc_Stopwatch.c b/libparc/parc/developer/parc_Stopwatch.c
new file mode 100644
index 00000000..dfd8a200
--- /dev/null
+++ b/libparc/parc/developer/parc_Stopwatch.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 <config.h>
+
+#include <sys/time.h>
+#include <inttypes.h>
+
+#if __APPLE__
+#include <mach/mach.h>
+#include <mach/clock.h>
+#include <mach/mach_time.h>
+#endif
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/developer/parc_Stopwatch.h>
+
+struct PARCStopwatch {
+ uint64_t start;
+// uint64_t stop;
+};
+
+static bool
+_parcStopwatch_Destructor(PARCStopwatch **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCStopwatch pointer.");
+
+ /* cleanup the instance fields here */
+ return true;
+}
+
+parcObject_ImplementAcquire(parcStopwatch, PARCStopwatch);
+
+parcObject_ImplementRelease(parcStopwatch, PARCStopwatch);
+
+parcObject_Override(PARCStopwatch, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcStopwatch_Destructor,
+ .release = (PARCObjectRelease *) parcStopwatch_Release,
+ .copy = (PARCObjectCopy *) parcStopwatch_Copy,
+ .toString = (PARCObjectToString *) parcStopwatch_ToString,
+ .equals = (PARCObjectEquals *) parcStopwatch_Equals,
+ .hashCode = (PARCObjectHashCode *) parcStopwatch_HashCode,
+ .toJSON = (PARCObjectToJSON *) parcStopwatch_ToJSON,
+ .display = (PARCObjectDisplay *) parcStopwatch_Display);
+
+void
+parcStopwatch_AssertValid(const PARCStopwatch *instance)
+{
+ assertTrue(parcStopwatch_IsValid(instance),
+ "PARCStopwatch is not valid.");
+}
+
+
+PARCStopwatch *
+parcStopwatch_Create(void)
+{
+ PARCStopwatch *result = parcObject_CreateInstance(PARCStopwatch);
+
+ if (result != NULL) {
+ result->start = 0;
+ }
+
+ return result;
+}
+
+PARCStopwatch *
+parcStopwatch_Copy(const PARCStopwatch *original)
+{
+ PARCStopwatch *result = parcStopwatch_Create();
+ result->start = original->start;
+
+ return result;
+}
+
+void
+parcStopwatch_Display(const PARCStopwatch *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCStopwatch@%p { .start=%" PRIu64 " }", instance, instance->start);
+}
+
+bool
+parcStopwatch_Equals(const PARCStopwatch *x, const PARCStopwatch *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (memcmp(&x->start, &y->start, sizeof(x->start)) == 0) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcStopwatch_HashCode(const PARCStopwatch *timer)
+{
+ PARCHashCode result = parcHashCode_Hash((uint8_t *) timer, sizeof(PARCStopwatch *));
+ return result;
+}
+
+bool
+parcStopwatch_IsValid(const PARCStopwatch *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcStopwatch_ToJSON(const PARCStopwatch *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ if (result != NULL) {
+ PARCJSON *start = parcJSON_Create();
+ parcJSON_AddInteger(start, "nanoseconds", instance->start);
+
+ parcJSON_AddObject(result, "start", start);
+ parcJSON_Release(&start);
+ }
+
+ return result;
+}
+
+char *
+parcStopwatch_ToString(const PARCStopwatch *instance)
+{
+ char *result = parcMemory_Format("PARCStopwatch@%p={ .start=%" PRIu64 " }", instance, instance->start);
+
+ return result;
+}
+
+#if __linux__
+void
+parcStopwatch_StartImpl(PARCStopwatch *timer, ...)
+{
+ struct timespec theTime;
+ clock_gettime(CLOCK_REALTIME_COARSE, &theTime);
+
+ timer->start = (uint64_t) (theTime.tv_sec * 1000000000) + theTime.tv_nsec;
+
+ va_list ap;
+ va_start(ap, timer);
+ PARCStopwatch *t;
+
+ while ((t = va_arg(ap, PARCStopwatch *)) != NULL) {
+ t->start = timer->start;
+ }
+}
+
+static inline uint64_t
+_parcStopwatch_Stop(PARCStopwatch *timer)
+{
+ struct timespec theTime;
+ clock_gettime(CLOCK_REALTIME_COARSE, &theTime);
+
+ uint64_t result = (uint64_t) (theTime.tv_sec * 1000000000) + theTime.tv_nsec;
+ return result;
+}
+#elif __APPLE__
+
+static mach_timebase_info_data_t _parcStopWatch_TimeBaseInfo;
+
+void
+parcStopwatch_StartImpl(PARCStopwatch *timer, ...)
+{
+ if (_parcStopWatch_TimeBaseInfo.denom == 0) {
+ mach_timebase_info(&_parcStopWatch_TimeBaseInfo);
+ }
+
+ timer->start = mach_absolute_time() * _parcStopWatch_TimeBaseInfo.numer / _parcStopWatch_TimeBaseInfo.denom;
+
+ va_list ap;
+ va_start(ap, timer);
+ PARCStopwatch *t;
+
+ while ((t = va_arg(ap, PARCStopwatch *)) != NULL) {
+ t->start = timer->start;
+ }
+}
+
+static inline uint64_t
+_parcStopwatch_Stop(PARCStopwatch *timer)
+{
+ uint64_t result = mach_absolute_time() * _parcStopWatch_TimeBaseInfo.numer / _parcStopWatch_TimeBaseInfo.denom;
+
+ return result;
+}
+#else
+void
+parcStopwatch_StartImpl(PARCStopwatch *timer, ...)
+{
+ struct timeval theTime;
+ gettimeofday(&theTime, NULL);
+
+ timer->start = (uint64_t) (theTime.tv_sec * 1000000000) + theTime.tv_usec * 1000;
+ va_list ap;
+ va_start(ap, timer);
+ PARCStopwatch *t;
+
+ while ((t = va_arg(ap, PARCStopwatch *)) != NULL) {
+ t->start = timer->start;
+ }
+}
+
+static inline uint64_t
+_parcStopwatch_Stop(PARCStopwatch *timer)
+{
+ struct timeval theTime;
+ gettimeofday(&theTime, NULL);
+
+ uint64_t result = theTime.tv_sec * 1000000000 + theTime.tv_usec * 1000;
+
+ return result;
+}
+#endif
+
+static inline uint64_t
+_parcStopWatch_ElapsedTimeNanos(PARCStopwatch *timer)
+{
+ return (_parcStopwatch_Stop(timer) - timer->start);
+}
+
+uint64_t
+parcStopwatch_ElapsedTimeNanos(PARCStopwatch *timer)
+{
+ return _parcStopWatch_ElapsedTimeNanos(timer);
+}
+
+uint64_t
+parcStopwatch_ElapsedTimeMicros(PARCStopwatch *timer)
+{
+ return _parcStopWatch_ElapsedTimeNanos(timer) / 1000;
+}
+
+uint64_t
+parcStopwatch_ElapsedTimeMillis(PARCStopwatch *timer)
+{
+ return _parcStopWatch_ElapsedTimeNanos(timer) / 1000000;
+}
diff --git a/libparc/parc/developer/parc_Stopwatch.h b/libparc/parc/developer/parc_Stopwatch.h
new file mode 100644
index 00000000..566bd314
--- /dev/null
+++ b/libparc/parc/developer/parc_Stopwatch.h
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Stopwatch.h
+ * @ingroup developer
+ * @brief Measure elapsed time
+ *
+ * A `PARCStopwatch` measures the time elapsed between the invocation of `parcStopwatch_Start()`
+ * and a subsequent invocation of one of the `parcStopwatch_ElapsedTime` functions.
+ * The `parcStopwatch_Start()` function may be called for a stopwatch effectively resetting the stopwatch to a new starting time.
+ *
+ */
+#ifndef PARCLibrary_parc_Stopwatch
+#define PARCLibrary_parc_Stopwatch
+#include <stdbool.h>
+#include <stdarg.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+struct PARCStopwatch;
+typedef struct PARCStopwatch PARCStopwatch;
+
+/**
+ * Increase the number of references to a `PARCStopwatch` instance.
+ *
+ * Note that new `PARCStopwatch` is not created,
+ * only that the given `PARCStopwatch` reference count is incremented.
+ * Discard the reference by invoking `parcStopwatch_Release`.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * PARCStopwatch *b = parcStopwatch_Acquire();
+ *
+ * parcStopwatch_Release(&a);
+ * parcStopwatch_Release(&b);
+ * }
+ * @endcode
+ */
+PARCStopwatch *parcStopwatch_Acquire(const PARCStopwatch *stopwatch);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcStopwatch_OptionalAssertValid(_instance_)
+#else
+# define parcStopwatch_OptionalAssertValid(_instance_) parcStopwatch_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCStopwatch` instance is valid.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * parcStopwatch_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcStopwatch_Release(&b);
+ * }
+ * @endcode
+ */
+void parcStopwatch_AssertValid(const PARCStopwatch *stopwatch);
+
+/**
+ * Create an instance of PARCStopwatch
+ *
+ * @return non-NULL A pointer to a valid PARCStopwatch instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * parcStopwatch_Release(&a);
+ * }
+ * @endcode
+ */
+PARCStopwatch *parcStopwatch_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] stopwatch A pointer to a valid PARCStopwatch instance.
+ * @param [in] other A pointer to a valid PARCStopwatch 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
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ * PARCStopwatch *b = parcStopwatch_Create();
+ *
+ * if (parcStopwatch_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcStopwatch_Release(&a);
+ * parcStopwatch_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcStopwatch_Equals
+ */
+int parcStopwatch_Compare(const PARCStopwatch *stopwatch, const PARCStopwatch *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 PARCStopwatch instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCStopwatch` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * PARCStopwatch *copy = parcStopwatch_Copy(&b);
+ *
+ * parcStopwatch_Release(&b);
+ * parcStopwatch_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCStopwatch *parcStopwatch_Copy(const PARCStopwatch *original);
+
+/**
+ * Print a human readable representation of the given `PARCStopwatch`.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * parcStopwatch_Display(a, 0);
+ *
+ * parcStopwatch_Release(&a);
+ * }
+ * @endcode
+ */
+void parcStopwatch_Display(const PARCStopwatch *stopwatch, int indentation);
+
+/**
+ * Determine if two `PARCStopwatch` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCStopwatch` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcStopwatch_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcStopwatch_Equals(x, y)` must return true if and only if
+ * `parcStopwatch_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcStopwatch_Equals(x, y)` returns true and
+ * `parcStopwatch_Equals(y, z)` returns true,
+ * then `parcStopwatch_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcStopwatch_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcStopwatch_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCStopwatch instance.
+ * @param [in] y A pointer to a valid PARCStopwatch instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ * PARCStopwatch *b = parcStopwatch_Create();
+ *
+ * if (parcStopwatch_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcStopwatch_Release(&a);
+ * parcStopwatch_Release(&b);
+ * }
+ * @endcode
+ * @see parcStopwatch_HashCode
+ */
+bool parcStopwatch_Equals(const PARCStopwatch *x, const PARCStopwatch *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 parcStopwatch_Equals} method,
+ * then calling the {@link parcStopwatch_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 parcStopwatch_Equals} function,
+ * then calling the `parcStopwatch_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * PARCHashCode hashValue = parcStopwatch_HashCode(buffer);
+ * parcStopwatch_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcStopwatch_HashCode(const PARCStopwatch *stopwatch);
+
+/**
+ * Determine if an instance of `PARCStopwatch` 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] stopwatch A pointer to a valid PARCStopwatch instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * if (parcStopwatch_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcStopwatch_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcStopwatch_IsValid(const PARCStopwatch *stopwatch);
+
+/**
+ * Release a previously acquired reference to the given `PARCStopwatch` 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
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * parcStopwatch_Release(&a);
+ * }
+ * @endcode
+ */
+void parcStopwatch_Release(PARCStopwatch **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCStopwatch 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
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * PARCJSON *json = parcStopwatch_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcStopwatch_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcStopwatch_ToJSON(const PARCStopwatch *stopwatch);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCStopwatch`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch 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
+ * {
+ * PARCStopwatch *a = parcStopwatch_Create();
+ *
+ * char *string = parcStopwatch_ToString(a);
+ *
+ * parcStopwatch_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcStopwatch_Display
+ */
+char *parcStopwatch_ToString(const PARCStopwatch *stopwatch);
+
+/**
+ * Start one or more PARCStopwatch instances.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ * @param [in] ... A variable argument list consisting of pointers to valid PARCStopwatch instances.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *A = parcStopwatch_Create();
+ * PARCStopwatch *B = parcStopwatch_Create();
+ * PARCStopwatch *C = parcStopwatch_Create();
+ *
+ * parcStopwatch_Start(A, B, C);
+ *
+ * }
+ * @endcode
+ */
+#define parcStopwatch_Start(...) parcStopwatch_StartImpl(__VA_ARGS__, NULL)
+
+/**
+ * Start one or more PARCStopwatch instances.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ * @param [in] ... A NULL termianted argument list consisting of pointers to valid PARCStopwatch instances.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCStopwatch *stopWatch = parcStopwatch_Create();
+ * parcStopwatch_StartImpl(stopWatch, NULL);
+ * }
+ * @endcode
+ */
+void parcStopwatch_StartImpl(PARCStopwatch *stopwatch, ...);
+
+/**
+ * Get the number of nanoseconds between the time the PARCStopwatch was started and the time of this function call.
+ *
+ * The accuracy is dependant upon the operating environment's time resolution.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ *
+ * @return The difference between the start and stop times nanoseconds.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+uint64_t parcStopwatch_ElapsedTimeNanos(PARCStopwatch *stopwatch);
+
+/**
+ * Get the number of microseconds between the time the PARCStopwatch was started and the time of this function call.
+ *
+ * The accuracy is dependant upon the operating environment's time resolution.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ *
+ * @return The difference between the start and stop times in microseconds.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+uint64_t parcStopwatch_ElapsedTimeMicros(PARCStopwatch *stopwatch);
+
+/**
+ * Get the number of milliseconds between the time the PARCStopwatch was started and the time of this function call.
+ *
+ * The accuracy is dependant upon the operating environment's time resolution.
+ *
+ * @param [in] stopwatch A pointer to a valid PARCStopwatch instance.
+ *
+ * @return The difference between the start and stop times in milliseconds.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+uint64_t parcStopwatch_ElapsedTimeMillis(PARCStopwatch *stopwatch);
+#endif
diff --git a/libparc/parc/developer/parc_Timing.h b/libparc/parc/developer/parc_Timing.h
new file mode 100755
index 00000000..bd5c3340
--- /dev/null
+++ b/libparc/parc/developer/parc_Timing.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Timing.h
+ * @ingroup developer
+ * @brief Macros for timing code
+ *
+ * These macros allow the developer to measure time spent in sections of code.
+ * On Intel platforms (i386 or x86_64), the timing is done with the TSC counter, so it will be measured in CPU cycles.
+ * On non-Intel Linux platforms, it will be be done with the nano-second oscillator clock (CLOCK_MONOTONIC_RAW).
+ * On Darwin, it will use the nano-second SYSTEM_CLOCK.
+ * Otherwise, uses gettimeofday(), which will be micro-second timing.
+ *
+ * This set of headers will define several macros for timing:
+ * parcTiming_Init(prefix)
+ * parcTiming_Fini(prefix)
+ * parcTiming_Start(prefix)
+ * parcTiming_Stop(prefix)
+ * (uint64_t) parcTiming_Delta(prefix)
+ *
+ * The units returned from parcTiming_Delta() will be consistent, but not necessarily
+ * related to wall clock time, real time, or any discernable time unit. For example, they
+ * may be in CPU instruction cycles or raw oscillator ticks or nano-seconds.
+ *
+ * These macros only work if the user defines PARCTIMING_ENABLE. Otherwise, they do not
+ * generate any instructions and parcTiming_Delta will always return 0.
+ *
+ * @code
+ * #define PARCTIMING_ENABLE 1
+ * #include <parc/developer/parc_Timing.h>
+ *
+ * void
+ * foo(void)
+ * {
+ * parcTiming_Init(_foo);
+ * // ... other stuff ..
+ * parcTiming_Start(_foo);
+ * // ... stuff to measure ...
+ * parcTiming_Stop(_foo);
+ *
+ * uint64_t delta = parcTiming_Delta(_foo);
+ * parcTiming_Fini(_foo)
+ * }
+ * @endcode
+ *
+ */
+#ifndef libparc_parc_Timing_h
+#define libparc_parc_Timing_h
+
+#if defined(PARCTIMING_ENABLE)
+// begin platform detection
+#if defined(__i386__) || defined(__x86_64__)
+#define PARCTIMING_INTEL
+#include <parc/developer/parc_TimingIntel.h>
+#elif defined(__APPLE__)
+#define PARCTIMING_DARWIN
+#include <parc/developer/parc_TimingDarwin.h>
+#elif defined(__linux__)
+#define PARCTIMING_LINUX
+#include <parc/developer/parc_TimingLinux.h>
+#else
+#define PARCTIMING_GENERIC
+#include <parc/developer/parc_TimingGeneric.h>
+#endif // platform detection
+#else // PARCTIMING_ENABLE
+#define _private_parcTiming_Init(prefix)
+#define _private_parcTiming_Start(prefix)
+#define _private_parcTiming_Stop(prefix)
+#define _private_parcTiming_Delta(prefix) ((uint64_t) 0)
+#define _private_parcTiming_Fini(prefix)
+#endif // PARCTIMING_ENABLE
+
+/**
+ * Initialize the timing facility for namespace prefix `prefix`
+ *
+ * Used inside a code block, this macro will define several variables prefixed with
+ * the name `prefix`. It may also allocate memory or system resources. It must be used
+ * within a function scope, not at a global scope.
+ *
+ * You must use parcTiming_Fini(prefix) when done with the timing facility.
+ *
+ * If `PARCTIMING_ENABLE` is not defined before including the header file, this function is a no-op.
+ *
+ * @param [in] prefix The namespace prefix used for variables in scope.
+ *
+ * Example:
+ * @code
+ * #define PARCTIMING_ENABLE 1
+ * #include <parc/developer/parc_Timing.h>
+ *
+ * void
+ * foo(void)
+ * {
+ * parcTiming_Init(_foo);
+ * parcTiming_Start(_foo);
+ * // ... stuff to measure ...
+ * parcTiming_Stop(_foo);
+ *
+ * uint64_t delta = parcTiming_Delta(_foo);
+ * parcTiming_Fini(_foo)
+ * }
+ * @endcode
+ */
+#define parcTiming_Init(prefix) _private_parcTiming_Init(prefix)
+
+/**
+ * Marks the time in the start variable
+ *
+ * Records the current time in the start variable for use by parcTiming_Delta().
+ *
+ * If PARCTIMING_ENABLE is not defined before including the header file, this function is a no-op.
+ *
+ * @param [in] prefix The namespace prefix used for variables in scope.
+ *
+ * Example:
+ * @code
+ * #define PARCTIMING_ENABLE 1
+ * #include <parc/developer/parc_Timing.h>
+ *
+ * void
+ * foo(void)
+ * {
+ * parcTiming_Init(_foo);
+ * parcTiming_Start(_foo);
+ * // ... stuff to measure ...
+ * parcTiming_Stop(_foo);
+ *
+ * uint64_t delta = parcTiming_Delta(_foo);
+ * parcTiming_Fini(_foo)
+ * }
+ * @endcode
+ */
+#define parcTiming_Start(prefix) _private_parcTiming_Start(prefix)
+
+/**
+ * Marks the time in the stop variable
+ *
+ * Records the current time in the stop variable for use by parcTiming_Delta().
+ *
+ * If PARCTIMING_ENABLE is not defined before including the header file, this function is a no-op.
+ *
+ * @param [in] prefix The namespace prefix used for variables in scope.
+ *
+ * Example:
+ * @code
+ * #define PARCTIMING_ENABLE 1
+ * #include <parc/developer/parc_Timing.h>
+ *
+ * void
+ * foo(void)
+ * {
+ * parcTiming_Init(_foo);
+ * parcTiming_Start(_foo);
+ * // ... stuff to measure ...
+ * parcTiming_Stop(_foo);
+ *
+ * uint64_t delta = parcTiming_Delta(_foo);
+ * parcTiming_Fini(_foo)
+ * }
+ * @endcode
+ */
+#define parcTiming_Stop(prefix) _private_parcTiming_Stop(prefix)
+
+/**
+ * Returns the number of ticks between calls to start and stop.
+ *
+ * The delta will be in whatever units the best clock and provide. It may be CPU cycles
+ * or oscillator ticks, or nanos, or in the worst case micros.
+ *
+ * If PARCTIMING_ENABLE is not defined before including the header file, this function is a no-op.
+ *
+ * @param [in] prefix The namespace prefix used for variables in scope.
+ *
+ * @return uint64_t The number of ticks between start and stop
+ *
+ * Example:
+ * @code
+ * #define PARCTIMING_ENABLE 1
+ * #include <parc/developer/parc_Timing.h>
+ *
+ * void
+ * foo(void)
+ * {
+ * parcTiming_Init(_foo);
+ * parcTiming_Start(_foo);
+ * // ... stuff to measure ...
+ * parcTiming_Stop(_foo);
+ *
+ * uint64_t delta = parcTiming_Delta(_foo);
+ * parcTiming_Fini(_foo)
+ * }
+ * @endcode
+ */
+#define parcTiming_Delta(prefix) _private_parcTiming_Delta(prefix)
+
+/**
+ * Finalized the timing, releasing any system resources or memory
+ *
+ * Must be called when done with each namespace initialized by parcTiming_Init().
+ *
+ * If PARCTIMING_ENABLE is not defined before including the header file, this function is a no-op.
+ *
+ * @param [in] prefix The namespace prefix used for variables in scope.
+ *
+ * Example:
+ * @code
+ * #define PARCTIMING_ENABLE 1
+ * #include <parc/developer/parc_Timing.h>
+ *
+ * void
+ * foo(void)
+ * {
+ * parcTiming_Init(_foo);
+ * parcTiming_Start(_foo);
+ * // ... stuff to measure ...
+ * parcTiming_Stop(_foo);
+ *
+ * uint64_t delta = parcTiming_Delta(_foo);
+ * parcTiming_Fini(_foo)
+ * }
+ * @endcode
+ */
+#define parcTiming_Fini(prefix) _private_parcTiming_Fini(prefix)
+#endif // libparc_parc_Timing_h
+
diff --git a/libparc/parc/developer/parc_TimingDarwin.h b/libparc/parc/developer/parc_TimingDarwin.h
new file mode 100755
index 00000000..7b2a100e
--- /dev/null
+++ b/libparc/parc/developer/parc_TimingDarwin.h
@@ -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.
+ */
+
+/**
+ * @file parc_TimingDarwin.h
+ * @brief Macros for timing code
+ *
+ * On linux will use clock_gettime with the MONOTONIC RAW clock, which does not speed up or slow down based on adj_time().
+ *
+ */
+#ifndef libparc_parc_TimingDarwin_h
+#define libparc_parc_TimingDarwin_h
+
+#ifdef PARCTIMING_DARWIN
+#include <stdint.h>
+#include <time.h>
+#include <mach/mach.h>
+#include <mach/clock.h>
+#include <mach/mach_time.h>
+
+/*
+ * This allocates the clock service which must be released in the Fini macro
+ */
+#define _private_parcTiming_Init(prefix) \
+ clock_serv_t prefix ## _clockService; \
+ mach_timespec_t prefix ## _ts0, prefix ## _ts1; \
+ host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &(prefix ## _clockService));
+
+#define _private_parcTiming_Start(prefix) \
+ clock_get_time((prefix ## _clockService), &(prefix ## _ts0));
+
+#define _private_parcTiming_Stop(prefix) \
+ clock_get_time((prefix ## _clockService), &(prefix ## _ts1));
+
+static inline uint64_t
+_parcTiming_Delta(const mach_timespec_t *t0, const mach_timespec_t *t1)
+{
+ // SUB_MACH_TIMESPEC(t1, t2) => t1 -= t2
+
+ mach_timespec_t delta;
+ memcpy(&delta, t1, sizeof(delta));
+ SUB_MACH_TIMESPEC(&delta, t0);
+
+ return (uint64_t) delta.tv_sec * 1000000000ULL + delta.tv_nsec;
+}
+
+#define _private_parcTiming_Delta(prefix) _parcTiming_Delta(&(prefix ## _ts0), &(prefix ## _ts1))
+
+#define _private_parcTiming_Fini(prefix) \
+ mach_port_deallocate(mach_task_self(), &(prefix ## _clockService));
+
+#endif // PARCTIMING_DARWIN
+#endif // libparc_parc_TimingDarwin_h
+
diff --git a/libparc/parc/developer/parc_TimingGeneric.h b/libparc/parc/developer/parc_TimingGeneric.h
new file mode 100755
index 00000000..8c1d4468
--- /dev/null
+++ b/libparc/parc/developer/parc_TimingGeneric.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 parc_TimingGeneric.h
+ * @brief Macros for timing code
+ *
+ * We cannot do any better than gettimeofday
+ *
+ */
+#ifndef libparc_parc_TimingLinux_h
+#define libparc_parc_TimingLinux_h
+
+#include <stdint.h>
+#include <time.h>
+#include <sys/time.h>
+
+#ifdef PARCTIMING_GENERIC
+
+#define _private_parcTiming_Init(prefix) \
+ struct timeval prefix ## _ts0, prefix ## _ts1, prefix ## _delta;
+
+#define _private_parcTiming_Start(prefix) \
+ gettimeofday(&(prefix ## _ts0), NULL);
+
+#define _private_parcTiming_Stop(prefix) \
+ gettimeofday(&(prefix ## _ts1), NULL);
+
+static inline uint64_t
+_parcTimingGeneric_Delta(const struct timeval *t0, const struct timeval *t1)
+{
+ struct timeval delta;
+ timersub(t1, t0, &delta);
+ return (uint64_t) delta.tv_sec * 1000000ULL + delta.tv_usec;
+}
+
+#define _private_parcTiming_Delta(prefix) _parcTimingGeneric_Delta(&(prefix ## _ts0), &(prefix ## _ts1))
+
+// No teardown work that we need to do
+#define _private_parcTiming_Fini(prefix)
+
+#endif // PARCTIMING_GENERIC
+#endif // libparc_parc_TimingLinux_h
+
diff --git a/libparc/parc/developer/parc_TimingIntel.c b/libparc/parc/developer/parc_TimingIntel.c
new file mode 100755
index 00000000..c690515c
--- /dev/null
+++ b/libparc/parc/developer/parc_TimingIntel.c
@@ -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.
+ */
+
+/**
+ * Executes either the RDTSC or RDTSCP instruction, depending on platform availability
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#define PARCTIMING_ENABLE
+#include <parc/developer/parc_Timing.h>
+
+#ifdef PARCTIMING_INTEL
+static bool _useRdtscp = false;
+static bool _needCheckRdtscp = true;
+
+#include <cpuid.h>
+
+static void
+_checkRdtscp(void)
+{
+ // See the CPUID instruction for description of the codes.
+
+ // determine the maximum extended information set
+ unsigned maxextended = __get_cpuid_max(0x80000000, NULL);
+
+ // RDTSCP status flag is in the 0x800000001 feature set
+ const unsigned feature = 0x80000001;
+ const unsigned rdtscp_feature = 1 << 27;
+
+ if (maxextended >= feature) {
+ unsigned eax, ebx, ecx, edx;
+
+ int success = __get_cpuid(feature, &eax, &ebx, &ecx, &edx);
+ if (success) {
+ _useRdtscp = (edx & rdtscp_feature ? true : false);
+ }
+ }
+}
+#endif // PARCTIMING_INTEL
+
+void
+parcTiminIntel_RuntimeInit(void)
+{
+#ifdef PARCTIMING_INTEL
+ if (_needCheckRdtscp) {
+ _needCheckRdtscp = false;
+ _checkRdtscp();
+ }
+#endif // PARCTIMING_INTEL
+}
+
+void
+parcTimingIntel_rdtsc(unsigned *hi, unsigned *lo)
+{
+ /*
+ * Older CPUs do not support RDTSCP, which is the better instruction to use.
+ * If we did not detect this opcode in autoconf, use the older RDTSC
+ */
+
+#ifdef PARCTIMING_INTEL
+ if (_useRdtscp) {
+ __asm volatile ("RDTSCP\n\t"
+ "mov %%edx,%0\n\t"
+ "mov %%eax,%1\n\t"
+ "CPUID\n\t" : "=r" (*hi), "=r" (*lo):: "%rax", "%rbx", "%rcx", "%rdx");
+ } else {
+ __asm volatile ("RDTSC\n\t"
+ "mov %%edx,%0\n\t"
+ "mov %%eax,%1\n\t"
+ "CPUID\n\t" : "=r" (*hi), "=r" (*lo):: "%rax", "%rbx", "%rcx", "%rdx");
+ }
+#endif // PARCTIMING_INTEL
+}
+
diff --git a/libparc/parc/developer/parc_TimingIntel.h b/libparc/parc/developer/parc_TimingIntel.h
new file mode 100755
index 00000000..4a90896d
--- /dev/null
+++ b/libparc/parc/developer/parc_TimingIntel.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 parc_TimingIntel.h
+ * @ingroup developer
+ * @brief Macros for timing code
+ *
+ * This code uses the Intel recommended benchmarking techniques described
+ * in the whitepaper "How to Benchmakr Code Execution Times on Intel (R) IA-32 and
+ * IA-64 Instruction Set Architectures" available at:
+ *
+ * http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf
+ *
+ *
+ */
+#ifndef libparc_parc_TimingIntel_h
+#define libparc_parc_TimingIntel_h
+
+#ifdef PARCTIMING_INTEL
+#include <stdint.h>
+#include <stdbool.h>
+
+/**
+ * Reads the TSC via the best available CPU instruction
+ *
+ * Will execute a RDTSC or RDTSCP instruction followed by an instruction pipeline block
+ * CPUID instruction.
+ *
+ * @param [out] hi The high-order 32-bits
+ * @param [out] lo The low-order 32-bits
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcTimingIntel_rdtsc(unsigned *hi, unsigned *lo);
+
+/**
+ * Checks initialization for RDTSCP instruction availability
+ *
+ * Checks if RDTSCP is availalbe on the system and sets a global.
+ *
+ * Example:
+ * @code
+ * {
+ * parcTiminIntel_RuntimeInit();
+ * }
+ * @endcode
+ */
+void parcTiminIntel_RuntimeInit(void);
+
+#define _private_parcTiming_Init(prefix) \
+ parcTiminIntel_RuntimeInit(); \
+ static unsigned prefix ## _cycles_low0, prefix ## _cycles_high0; \
+ static unsigned prefix ## _cycles_low1, prefix ## _cycles_high1; \
+ \
+ __asm volatile ("CPUID\n\t" "RDTSC\n\t" \
+ "mov %%edx, %0\n\t" \
+ "mov %%eax, %1\n\t" : "=r" (prefix ## _cycles_high0), "=r" (prefix ## _cycles_low0):: \
+ "%rax", "%rbx", "%rcx", "%rdx"); \
+ parcTimingIntel_rdtsc(&(prefix ## _cycles_high1), &(prefix ## _cycles_low1)); \
+ __asm volatile ("CPUID\n\t" \
+ "RDTSC\n\t" \
+ "mov %%edx, %0\n\t" \
+ "mov %%eax, %1\n\t" : "=r" (prefix ## _cycles_high0), "=r" (prefix ## _cycles_low0):: \
+ "%rax", "%rbx", "%rcx", "%rdx"); \
+ parcTimingIntel_rdtsc(&(prefix ## _cycles_high1), &(prefix ## _cycles_low1));
+
+#define _private_parcTiming_Start(prefix) \
+ parcTimingIntel_rdtsc(&(prefix ## _cycles_high0), &(prefix ## _cycles_low0));
+
+#define _private_parcTiming_Stop(prefix) \
+ parcTimingIntel_rdtsc(&(prefix ## _cycles_high1), &(prefix ## _cycles_low1));
+
+#define _private_parcTiming_CalculateStartTime(prefix) (((uint64_t) prefix ## _cycles_high0 << 32) | prefix ## _cycles_low0)
+#define _private_parcTiming_CalculateStopTime(prefix) (((uint64_t) prefix ## _cycles_high1 << 32) | prefix ## _cycles_low1)
+
+#define _private_parcTiming_Delta(prefix) \
+ (_private_parcTiming_CalculateStopTime(prefix) - _private_parcTiming_CalculateStartTime(prefix))
+
+// No teardown work that we need to do
+#define _private_parcTiming_Fini(prefix)
+
+#endif // PARCTIMING_INTEL
+#endif // libparc_parc_TimingIntel_h
+
diff --git a/libparc/parc/developer/parc_TimingLinux.h b/libparc/parc/developer/parc_TimingLinux.h
new file mode 100755
index 00000000..3dd36205
--- /dev/null
+++ b/libparc/parc/developer/parc_TimingLinux.h
@@ -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.
+ */
+
+/**
+ * @file parc_TimingLinux.h
+ * @brief Macros for timing code
+ *
+ * On linux will use clock_gettime with the MONOTONIC RAW clock, which does not speed up or slow down based on adj_time().
+ *
+ */
+#ifndef libparc_parc_TimingLinux_h
+#define libparc_parc_TimingLinux_h
+
+#ifdef PARCTIMING_LINUX
+#include <stdint.h>
+#include <time.h>
+#include <sys/time.h>
+
+#define _private_parcTiming_Init(prefix) \
+ struct timespec prefix ## _ts0, prefix ## _ts1;
+
+#define _private_parcTiming_Start(prefix) \
+ clock_gettime(CLOCK_MONOTONIC_RAW, &(prefix ## _ts0));
+
+#define _private_parcTiming_Stop(prefix) \
+ clock_gettime(CLOCK_MONOTONIC_RAW, &(prefix ## _ts1));
+
+static inline uint64_t
+_parcTimingLinux_Delta(const struct timespec *t0, const struct timespec *t1)
+{
+ struct timespec delta;
+
+ delta.tv_sec = t1->tv_sec - t0->tv_sec;
+ delta.tv_nsec = t1->tv_nsec - t0->tv_nsec;
+ if (delta.tv_nsec < 0) {
+ --delta.tv_sec;
+ delta.tv_nsec += 1000000000;
+ }
+
+ return (uint64_t) delta.tv_sec * 1000000000ULL + delta.tv_nsec;
+}
+
+#define _private_parcTiming_Delta(prefix) _parcTimingLinux_Delta(&(prefix ## _ts0), &(prefix ## _ts1))
+
+// No teardown work that we need to do
+#define _private_parcTiming_Fini(prefix)
+
+#endif // PARCTIMING_LINUX
+#endif // libparc_parc_TimingLinux_h
+
diff --git a/libparc/parc/developer/test/.gitignore b/libparc/parc/developer/test/.gitignore
new file mode 100644
index 00000000..a6e5249b
--- /dev/null
+++ b/libparc/parc/developer/test/.gitignore
@@ -0,0 +1,2 @@
+test_parc_Timing
+test_parc_Timer
diff --git a/libparc/parc/developer/test/CMakeLists.txt b/libparc/parc/developer/test/CMakeLists.txt
new file mode 100644
index 00000000..82cb60e6
--- /dev/null
+++ b/libparc/parc/developer/test/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(TestsExpectedToPass
+ test_parc_Stopwatch
+ test_parc_Timing
+ )
+
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
+
diff --git a/libparc/parc/developer/test/test_parc_Stopwatch.c b/libparc/parc/developer/test/test_parc_Stopwatch.c
new file mode 100644
index 00000000..0f205ec7
--- /dev/null
+++ b/libparc/parc/developer/test/test_parc_Stopwatch.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_Stopwatch.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <stdio.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(parc_Timer)
+{
+ // 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(parc_Timer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Timer)
+{
+ 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)
+{
+ PARCStopwatch *instance = parcStopwatch_Create();
+ assertNotNull(instance, "Expected non-null result from parcStopwatch_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcStopwatch_Acquire, instance);
+
+ parcStopwatch_Release(&instance);
+ assertNull(instance, "Expected null result from parcStopwatch_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcStopwatch_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, parcStopwatch_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, parcStopwatch_Display);
+ LONGBOW_RUN_TEST_CASE(Object, parcStopwatch_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcStopwatch_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcStopwatch_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcStopwatch_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcStopwatch_ToString);
+}
+
+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, parcStopwatch_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Object, parcStopwatch_Copy)
+{
+ PARCStopwatch *instance = parcStopwatch_Create();
+ PARCStopwatch *copy = parcStopwatch_Copy(instance);
+ assertTrue(parcStopwatch_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcStopwatch_Release(&instance);
+ parcStopwatch_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Object, parcStopwatch_Display)
+{
+ PARCStopwatch *instance = parcStopwatch_Create();
+ parcStopwatch_Display(instance, 0);
+ parcStopwatch_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcStopwatch_Equals)
+{
+ PARCStopwatch *x = parcStopwatch_Create();
+ PARCStopwatch *y = parcStopwatch_Create();
+ PARCStopwatch *z = parcStopwatch_Create();
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcStopwatch_Release(&x);
+ parcStopwatch_Release(&y);
+ parcStopwatch_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Object, parcStopwatch_HashCode)
+{
+ PARCStopwatch *x = parcStopwatch_Create();
+ PARCStopwatch *y = parcStopwatch_Create();
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcStopwatch_Release(&x);
+ parcStopwatch_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Object, parcStopwatch_IsValid)
+{
+ PARCStopwatch *instance = parcStopwatch_Create();
+ assertTrue(parcStopwatch_IsValid(instance), "Expected parcStopwatch_Create to result in a valid instance.");
+
+ parcStopwatch_Release(&instance);
+ assertFalse(parcStopwatch_IsValid(instance), "Expected parcStopwatch_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcStopwatch_ToJSON)
+{
+ PARCStopwatch *instance = parcStopwatch_Create();
+
+ PARCJSON *json = parcStopwatch_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcStopwatch_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcStopwatch_ToString)
+{
+ PARCStopwatch *instance = parcStopwatch_Create();
+
+ char *string = parcStopwatch_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcStopwatch_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcStopwatch_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, parcStopwatch_Multi);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcStopwatch_ElapsedTimeNanos);
+}
+
+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, parcStopwatch_Multi)
+{
+ PARCStopwatch *a = parcStopwatch_Create();
+ PARCStopwatch *b = parcStopwatch_Create();
+ PARCStopwatch *c = parcStopwatch_Create();
+
+ parcStopwatch_Start(a, b, c);
+ sleep(2);
+ uint64_t nanos = parcStopwatch_ElapsedTimeNanos(a);
+ printf("%llu %llu\n", nanos, nanos / 1000000000);
+ if (nanos > (3000000000)) {
+ parcStopwatch_Display(a, 0);
+ }
+
+ parcStopwatch_Release(&a);
+ parcStopwatch_Release(&b);
+ parcStopwatch_Release(&c);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcStopwatch_ElapsedTimeNanos)
+{
+ PARCStopwatch *instance = parcStopwatch_Create();
+
+ parcStopwatch_StartImpl(instance, NULL);
+ sleep(2);
+ uint64_t nanos = parcStopwatch_ElapsedTimeNanos(instance);
+ printf("%llu %llu\n", nanos, nanos / 1000000000);
+ if (nanos > (3000000000)) {
+ parcStopwatch_Display(instance, 0);
+ }
+
+ parcStopwatch_Release(&instance);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Timer);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libparc/parc/developer/test/test_parc_Timing.c b/libparc/parc/developer/test/test_parc_Timing.c
new file mode 100755
index 00000000..eafa2350
--- /dev/null
+++ b/libparc/parc/developer/test/test_parc_Timing.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>
+
+#define PARCTIMING_ENABLE 1
+#include "../parc_Timing.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_Timing)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Timing)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Timing)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcTiming_One);
+ LONGBOW_RUN_TEST_CASE(Global, parcTiming_Two);
+}
+
+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;
+}
+
+static void
+_delay(void)
+{
+ int count = 0;
+ for (int i = 0; i < 100000; i++) {
+ count++;
+ }
+}
+
+LONGBOW_TEST_CASE(Global, parcTiming_One)
+{
+ parcTiming_Init(foo);
+ parcTiming_Start(foo);
+ _delay();
+ parcTiming_Stop(foo);
+
+ uint64_t delta = parcTiming_Delta(foo);
+
+ assertTrue(delta > 0, "Did not measure a delta, expected positive");
+ parcTiming_Fini(foo);
+}
+
+/*
+ * Test two clocks at the same time
+ */
+LONGBOW_TEST_CASE(Global, parcTiming_Two)
+{
+ parcTiming_Init(outer);
+ parcTiming_Init(inner);
+
+ parcTiming_Start(outer);
+ _delay();
+
+ parcTiming_Start(inner);
+ _delay();
+ parcTiming_Stop(inner);
+
+ parcTiming_Stop(outer);
+
+ uint64_t deltaOuter = parcTiming_Delta(outer);
+ uint64_t deltaInner = parcTiming_Delta(inner);
+
+ assertTrue(deltaOuter > deltaInner,
+ "expected the outer timer to be greater than the inner timer: outer %" PRIu64 ", inner %" PRIu64,
+ deltaOuter, deltaInner);
+
+ printf("outer %" PRIu64 ", inner %" PRIu64, deltaOuter, deltaInner);
+
+ parcTiming_Fini(outer);
+ parcTiming_Fini(inner);
+}
+
+// ===============================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Timing);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/libparc_About.c b/libparc/parc/libparc_About.c
new file mode 100644
index 00000000..0120caf1
--- /dev/null
+++ b/libparc/parc/libparc_About.c
@@ -0,0 +1,44 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170206.46e2c73a 2017-02-06T08:50:09Z
+
+#include "libparc_About.h"
+
+const char *libparc_What = "@(#)" "The PARC C Library " RELEASE_VERSION " 2017-02-15T10:32:06.494538"
+ "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates.";
+
+const char *
+libparcAbout_Name(void)
+{
+ return "The PARC C Library";
+}
+
+const char *
+libparcAbout_Version(void)
+{
+ return RELEASE_VERSION;
+}
+
+const char *
+libparcAbout_About(void)
+{
+ return "The PARC C Library "RELEASE_VERSION " 2017-02-15T10:32:06.494538" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+libparcAbout_MiniNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+libparcAbout_ShortNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+libparcAbout_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/libparc/parc/libparc_About.h b/libparc/parc/libparc_About.h
new file mode 100755
index 00000000..39fee44f
--- /dev/null
+++ b/libparc/parc/libparc_About.h
@@ -0,0 +1,54 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170206.46e2c73a 2017-02-06T08:50:09Z
+
+#ifndef libparc_About_h
+#define libparc_About_h
+/**
+ * Embedded string containing information for the what(1) command.
+ *
+ */
+extern const char *libparc_What;
+
+/**
+ * Return the name as a C string.
+ *
+ * @return The name as a C string.
+ */
+const char *libparcAbout_Name(void);
+
+/**
+ * Return the version as a C string.
+ *
+ * @return The version as a C string.
+ */
+const char *libparcAbout_Version(void);
+
+/**
+ * Return the About text as a C string.
+ *
+ * @return The About text as a C string.
+ */
+const char *libparcAbout_About(void);
+
+/**
+ * Return the minimum copyright notice as a C string.
+ *
+ * @return The minimum copyright notice as a C string.
+ */
+const char *libparcAbout_MiniNotice(void);
+
+/**
+ * Return the short copyright notice as a C string.
+ *
+ * @return The short copyright notice as a C string.
+ */
+const char *libparcAbout_ShortNotice(void);
+
+/**
+ * Return the long copyright notice as a C string.
+ *
+ * @return The long copyright notice as a C string.
+ */
+const char *libparcAbout_LongNotice(void);
+
+#endif // libparc_About_h
diff --git a/libparc/parc/logging/parc_Log.c b/libparc/parc/logging/parc_Log.c
new file mode 100755
index 00000000..e3948c36
--- /dev/null
+++ b/libparc/parc/logging/parc_Log.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 <config.h>
+
+#include <stdio.h>
+#include <sys/time.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/logging/parc_Log.h>
+#include <parc/logging/parc_LogReporter.h>
+
+struct PARCLog {
+ char *hostName;
+ char *applicationName;
+ char *processId;
+ uint64_t messageId;
+ PARCLogLevel level;
+ PARCLogReporter *reporter;
+};
+
+static void
+_parcLogger_Destroy(PARCLog **loggerPtr)
+{
+ PARCLog *logger = *loggerPtr;
+
+ parcMemory_Deallocate((void **) &logger->hostName);
+ parcMemory_Deallocate((void **) &logger->applicationName);
+ parcMemory_Deallocate((void **) &logger->processId);
+ parcLogReporter_Release(&logger->reporter);
+}
+
+parcObject_ExtendPARCObject(PARCLog, _parcLogger_Destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static const char *_nilvalue = "-";
+
+PARCLog *
+parcLog_Create(const char *hostName, const char *applicationName, const char *processId, PARCLogReporter *reporter)
+{
+ if (applicationName == NULL) {
+ applicationName = _nilvalue;
+ }
+ if (hostName == NULL) {
+ hostName = _nilvalue;
+ }
+ if (processId == NULL) {
+ processId = _nilvalue;
+ }
+
+ PARCLog *result = parcObject_CreateInstance(PARCLog);
+ if (result == NULL) {
+ trapOutOfMemory("Creating an instance of PARCLog.");
+ }
+
+ result->hostName = parcMemory_StringDuplicate(hostName, strlen(hostName));
+ result->applicationName = parcMemory_StringDuplicate(applicationName, strlen(applicationName));
+ result->processId = parcMemory_StringDuplicate(processId, strlen(processId));
+ result->messageId = 0;
+ result->level = PARCLogLevel_Off;
+ result->reporter = parcLogReporter_Acquire(reporter);
+ return result;
+}
+
+parcObject_ImplementAcquire(parcLog, PARCLog);
+
+parcObject_ImplementRelease(parcLog, PARCLog);
+
+
+PARCLogLevel
+parcLog_GetLevel(const PARCLog *log)
+{
+ return log->level;
+}
+
+PARCLogLevel
+parcLog_SetLevel(PARCLog *logger, const PARCLogLevel level)
+{
+ PARCLogLevel oldLevel = logger->level;
+ logger->level = level;
+ return oldLevel;
+}
+
+static PARCLogEntry *
+_parcLog_CreateEntry(PARCLog *log, PARCLogLevel level, uint64_t messageId, const char *format, va_list ap)
+{
+ char *cString;
+ int nwritten = vasprintf(&cString, format, ap);
+ assertTrue(nwritten >= 0, "Error calling vasprintf");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+
+ PARCBuffer *payload = parcBuffer_AllocateCString(cString);
+ PARCLogEntry *result = parcLogEntry_Create(level,
+ log->hostName,
+ log->applicationName,
+ log->processId,
+ messageId,
+ timeStamp,
+ payload);
+ parcBuffer_Release(&payload);
+
+ free(cString);
+ return result;
+}
+
+bool
+parcLog_MessageVaList(PARCLog *log, PARCLogLevel level, uint64_t messageId, const char *format, va_list ap)
+{
+ bool result = false;
+
+ if (parcLog_IsLoggable(log, level)) {
+ PARCLogEntry *entry = _parcLog_CreateEntry(log, level, messageId, format, ap);
+
+ parcLogReporter_Report(log->reporter, entry);
+ parcLogEntry_Release(&entry);
+ result = true;
+ }
+ return result;
+}
+
+bool
+parcLog_Message(PARCLog *log, PARCLogLevel level, uint64_t messageId, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ bool result = parcLog_MessageVaList(log, level, messageId, format, ap);
+ va_end(ap);
+
+ return result;
+}
+
+bool
+parcLog_Warning(PARCLog *logger, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ bool result = parcLog_MessageVaList(logger, PARCLogLevel_Warning, 0, format, ap);
+ va_end(ap);
+
+ return result;
+}
+
+bool
+parcLog_Info(PARCLog *logger, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ bool result = parcLog_MessageVaList(logger, PARCLogLevel_Info, 0, format, ap);
+ va_end(ap);
+
+ return result;
+}
+
+bool
+parcLog_Notice(PARCLog *logger, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ bool result = parcLog_MessageVaList(logger, PARCLogLevel_Notice, 0, format, ap);
+ va_end(ap);
+
+ return result;
+}
+
+bool
+parcLog_Debug(PARCLog *logger, const char *format, ...)
+{
+ bool result = false;
+
+ if (parcLog_IsLoggable(logger, PARCLogLevel_Debug)) {
+ va_list ap;
+ va_start(ap, format);
+ result = parcLog_MessageVaList(logger, PARCLogLevel_Debug, 0, format, ap);
+ va_end(ap);
+ }
+
+ return result;
+}
+
+bool
+parcLog_Error(PARCLog *logger, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ bool result = parcLog_MessageVaList(logger, PARCLogLevel_Error, 0, format, ap);
+ va_end(ap);
+
+ return result;
+}
+
+bool
+parcLog_Critical(PARCLog *logger, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ bool result = parcLog_MessageVaList(logger, PARCLogLevel_Critical, 0, format, ap);
+ va_end(ap);
+
+ return result;
+}
+
+bool
+parcLog_Alert(PARCLog *logger, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ bool result = parcLog_MessageVaList(logger, PARCLogLevel_Alert, 0, format, ap);
+ va_end(ap);
+
+ return result;
+}
+
+bool
+parcLog_Emergency(PARCLog *logger, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ bool result = parcLog_MessageVaList(logger, PARCLogLevel_Emergency, 0, format, ap);
+ va_end(ap);
+
+ return result;
+}
diff --git a/libparc/parc/logging/parc_Log.h b/libparc/parc/logging/parc_Log.h
new file mode 100644
index 00000000..29e401e0
--- /dev/null
+++ b/libparc/parc/logging/parc_Log.h
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Log.h
+ * @brief Event logging.
+ *
+ * This is an logging mechanism patterned after the Syslog logging protocol (RFC 5424),
+ * and influenced by `java.util.logging` and Apache Log4J.
+ *
+ * The lifecycle of a `PARCLog` starts with creating an instance via `parcLog_Create`
+ * and calling the various functions to emit log messages.
+ *
+ * Finally the log is released via `parcLog_Release` which ensures
+ * that any queued log messages are transmitted and resources are released.
+ *
+ * Every PARCLog instance has a logging level, a threshold that is set via `parcLog_SetLevel`
+ * that determines what kind of PARCLogEntry instances are actually logged.
+ * The PARCLogLevel PARCLogLevel_Emergency is always logged regardless of the current logging level.
+ *
+ */
+#ifndef libparc_parc_Logger_h
+#define libparc_parc_Logger_h
+
+#include <stdarg.h>
+
+#include <parc/logging/parc_LogReporter.h>
+#include <parc/logging/parc_LogEntry.h>
+#include <parc/logging/parc_LogLevel.h>
+
+struct PARCLog;
+typedef struct PARCLog PARCLog;
+
+/**
+ * Create a valid PARCLog instance.
+ *
+ * The initial instance's log level is set to `PARCLogLevel_Off`.
+ *
+ * @param [in] hostName A pointer to a nul-terminated C string, or NULL (See {@link PARCLogEntry}).
+ * @param [in] applicationName A pointer to a nul-terminated C string, or NULL (See {@link PARCLogEntry}).
+ * @param [in] processId A pointer to a nul-terminated C string, or NULL (See {@link PARCLogEntry}).
+ * @param [in] reporter A pointer to a valid `PARCLogReporter` instance.
+ *
+ * @return non-NULL A valid PARCLog instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ *
+ * PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ *
+ * parcOutputStream_Release(&output);
+ * parcFileOutputStream_Release(&fileOutput);
+ *
+ * PARCLog *log = parcLog_Create("localhost", "myApp", "daemon", reporter);
+ * parcLogReporter_Release(&reporter);
+ * }
+ * @endcode
+ */
+PARCLog *parcLog_Create(const char *hostName, const char *applicationName, const char *processId, PARCLogReporter *reporter);
+
+/**
+ * Increase the number of references to a `PARCLog`.
+ *
+ * Note that new `PARCLog` is not created,
+ * only that the given `PARCLog` reference count is incremented.
+ * Discard the reference by invoking `parcLog_Release`.
+ *
+ * @param [in] parcLog A pointer to a `PARCLog` instance.
+ *
+ * @return The input `PARCLog` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ *
+ * PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ *
+ * parcOutputStream_Release(&output);
+ * parcFileOutputStream_Release(&fileOutput);
+ *
+ * PARCLog *log = parcLog_Create("localhost", "myApp", "daemon", reporter);
+ *
+ * PARCLog *x_2 = parcLog_Acquire(log);
+ *
+ * parcLog_Release(&log);
+ * parcLog_Release(&x_2);
+ * }
+ * @endcode
+ */
+PARCLog *parcLog_Acquire(const PARCLog *parcLog);
+
+/**
+ * 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] logPtr A pointer to a PARCLog instance pointer, which will be set to zero on return.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ *
+ * PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ *
+ * parcOutputStream_Release(&output);
+ * parcFileOutputStream_Release(&fileOutput);
+ *
+ * PARCLog *log = parcLog_Create("localhost", "myApp", "daemon", reporter);
+ * parcLogReporter_Release(&reporter);
+ *
+ * parcLog_Release(&log);
+ * }
+ * @endcode
+ */
+void parcLog_Release(PARCLog **logPtr);
+
+/**
+ * Set the log severity level to the given value.
+ *
+ * The level is the maximum severity that will be logged via the PARCLogReporter.
+ * The log severity PARCLogLevel_Emergency cannot be blocked.
+ *
+ * @param [in] log A pointer to valid instance of PARCLog.
+ * @param [in] level A pointer to valid instance of PARCLogLevel.
+ *
+ * @return The previous value of the threshold.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ *
+ * PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ *
+ * parcOutputStream_Release(&output);
+ * parcFileOutputStream_Release(&fileOutput);
+ *
+ * PARCLog *log = parcLog_Create("localhost", "myApp", "daemon", reporter);
+ * parcLogReporter_Release(&reporter);
+ *
+ * PARCLogLevel old = parcLog_SetLevel(log, PARCLogLevel_Warning);
+ *
+ * parcLog_SetLevel(log, old);
+ *
+ * parcLog_Release(&log);
+ * }
+ * @endcode
+ */
+PARCLogLevel parcLog_SetLevel(PARCLog *log, const PARCLogLevel level);
+
+/**
+ * Get the severity level of the given PARCLog instance.
+ *
+ * The level is the maximum severity that will be logged via the PARCLogReporter.
+ * The log severity PARCLogLevel_Emergency cannot be blocked.
+ *
+ * @param [in] log A pointer to valid instance of PARCLog.
+ *
+ * @return The severity level of the given PARCLog instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ *
+ * PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ *
+ * parcOutputStream_Release(&output);
+ * parcFileOutputStream_Release(&fileOutput);
+ *
+ * PARCLog *log = parcLog_Create("localhost", "myApp", "daemon", reporter);
+ * parcLogReporter_Release(&reporter);
+ *
+ * PARCLogLevel level = parcLog_GetLevel(log, PARCLogLevel_Warning);
+ *
+ * parcLog_Release(&log);
+ * }
+ * @endcode
+ */
+PARCLogLevel parcLog_GetLevel(const PARCLog *log);
+
+/**
+ * Test if a PARCLogLevel would be logged by the current state of the given PARCLog instance.
+ *
+ * @param [in] log A pointer to valid instance of PARCLog.
+ * @param [in] level An instance of PARCLogLevel.
+ *
+ * @return true A PARCLogEntry of the given level would be logged.
+ * @return false A PARCLogEntry of the given level would be logged.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ *
+ * PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ *
+ * parcOutputStream_Release(&output);
+ * parcFileOutputStream_Release(&fileOutput);
+ *
+ * PARCLog *log = parcLog_Create("localhost", "myApp", "daemon", reporter);
+ * parcLogReporter_Release(&reporter);
+ *
+ * if (parcLog_IsLoggable(log, PARCLogLevel_Warning)) {
+ * printf("Logging is set to Warning severity level\n");
+ * }
+ *
+ * parcLog_Release(&log);
+ * }
+ * @endcode
+ */
+
+#define parcLog_IsLoggable(_log_, _level_) \
+ (_level_ == PARCLogLevel_Emergency) || (parcLogLevel_Compare(parcLog_GetLevel(_log_), _level_) >= 0)
+//bool parcLog_IsLoggable(const PARCLog *log, const PARCLogLevel level);
+
+/**
+ * Compose and emit a log message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] level An instance of PARCLogLevel.
+ * @param [in] messageId A value for the message identifier.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ap A `va_list` representing the parameters for the format specification.
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower than the specified PARCLogLevel.
+ *
+ * Example:
+ * @code
+ * parcLog_MessageVaList(log, PARCLogLevel_Warning, 123, "This is a warning message.");
+ * @endcode
+ */
+bool parcLog_MessageVaList(PARCLog *log, PARCLogLevel level, uint64_t messageId, const char *format, va_list ap);
+
+/**
+ * Compose and emit a log message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] level An instance of PARCLogLevel.
+ * @param [in] messageId A value for the message identifier.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower than the specified PARCLogLevel.
+ *
+ * Example:
+ * @code
+ * parcLog_Message(log, PARCLogLevel_Warning, "This is a warning message.");
+ * @endcode
+ */
+bool parcLog_Message(PARCLog *log, PARCLogLevel level, uint64_t messageId, const char *restrict format, ...);
+
+/**
+ * Compose and emit a PARCLogLevel_Warning message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower.
+ *
+ * Example:
+ * @code
+ * parcLog_Warning(log, "This is a warning message.");
+ * @endcode
+ */
+bool parcLog_Warning(PARCLog *log, const char *restrict format, ...);
+
+/**
+ * Compose and emit a PARCLogLevel_Message level message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower.
+ *
+ * Example:
+ * @code
+ * parcLog_Info(log, "This is an info message.");
+ * @endcode
+ */
+bool parcLog_Info(PARCLog *log, const char *restrict format, ...);
+
+/**
+ * Compose and emit a PARCLogLevel_Notice level message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower.
+ *
+ * Example:
+ * @code
+ * parcLog_Notice(log, "This is a notice message.");
+ * @endcode
+ */
+bool parcLog_Notice(PARCLog *log, const char *restrict format, ...);
+
+/**
+ * Compose and emit a PARCLogLevel_Debug level message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower.
+ *
+ * Example:
+ * @code
+ * parcLog_DebugMessage(log, "This is a debug message.");
+ * @endcode
+ */
+bool parcLog_Debug(PARCLog *log, const char *restrict format, ...);
+
+/**
+ * Compose and emit a PARCLogLevel_Error level message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower.
+ *
+ * Example:
+ * @code
+ * parcLog_ErrorMessage(log, "This is an error message.");
+ * @endcode
+ */
+bool parcLog_Error(PARCLog *log, const char *restrict format, ...);
+
+/**
+ * Compose and emit a PARCLogLevel_Critical level message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower.
+ *
+ * Example:
+ * @code
+ * parcLog_CriticalMessage(log, "This is a critical message.");
+ * @endcode
+ */
+bool parcLog_Critical(PARCLog *log, const char *restrict format, ...);
+
+/**
+ * Compose and emit a PARCLogLevel_Alert level message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower.
+ *
+ * Example:
+ * @code
+ * parcLog_AlertMessage(log, "This is an alert message.");
+ * @endcode
+ */
+bool parcLog_Alert(PARCLog *log, const char *restrict format, ...);
+
+/**
+ * Compose and emit a PARCLogLevel_Emergency level message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower.
+ *
+ * Example:
+ * @code
+ * parcLog_EmergencyMessage(log, "This is an emergency message.");
+ * @endcode
+ */
+bool parcLog_Emergency(PARCLog *log, const char *restrict format, ...);
+#endif // libparc_parc_Logger_h
diff --git a/libparc/parc/logging/parc_LogEntry.c b/libparc/parc/logging/parc_LogEntry.c
new file mode 100644
index 00000000..f84e3719
--- /dev/null
+++ b/libparc/parc/logging/parc_LogEntry.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <inttypes.h>
+#include <stdarg.h>
+
+#include <parc/logging/parc_LogEntry.h>
+
+#include <parc/algol/parc_Time.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/logging/parc_LogLevel.h>
+
+static const char _parcLog_Version = 1;
+
+struct PARCLogEntry {
+ PARCLogLevel level;
+ char version;
+ struct timeval timeStamp;
+ char *hostName;
+ char *applicationName;
+ char *processName;
+ uint64_t messageId;
+
+ PARCBuffer *payload;
+};
+
+static void
+_parcLogEntry_Destroy(PARCLogEntry **entryPtr)
+{
+ PARCLogEntry *entry = *entryPtr;
+
+ parcMemory_Deallocate((void **) &entry->hostName);
+ parcMemory_Deallocate((void **) &entry->applicationName);
+ parcMemory_Deallocate((void **) &entry->processName);
+ parcBuffer_Release(&entry->payload);
+}
+
+static char *
+_toString(const PARCLogEntry *entry)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ parcBufferComposer_Format(composer, "%ld.%06d %d ",
+ (long) entry->timeStamp.tv_sec, (int) entry->timeStamp.tv_usec, entry->level);
+
+ size_t position = parcBuffer_Position(entry->payload);
+ parcBufferComposer_PutBuffer(composer, entry->payload);
+ parcBuffer_SetPosition(entry->payload, position);
+
+ PARCBuffer *buffer = parcBufferComposer_GetBuffer(composer);
+ parcBuffer_Rewind(buffer);
+
+ char *result = parcBuffer_ToString(buffer);
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+parcObject_ExtendPARCObject(PARCLogEntry, _parcLogEntry_Destroy, NULL, _toString, NULL, NULL, NULL, NULL);
+
+PARCLogEntry *
+parcLogEntry_Create(PARCLogLevel level,
+ const char *hostName,
+ const char *applicationName,
+ const char *processName,
+ const uint64_t messageId,
+ const struct timeval timeStamp,
+ PARCBuffer *payload)
+{
+ PARCLogEntry *result = parcObject_CreateInstance(PARCLogEntry);
+ if (result == NULL) {
+ trapOutOfMemory("Creating an instance of PARCLogEntry.");
+ }
+ result->version = _parcLog_Version;
+ result->timeStamp = timeStamp;
+ result->hostName = parcMemory_StringDuplicate(hostName, strlen(hostName));
+ result->applicationName = parcMemory_StringDuplicate(applicationName, strlen(applicationName));
+ result->processName = parcMemory_StringDuplicate(processName, strlen(processName));
+ result->messageId = messageId;
+ result->level = level;
+ result->payload = parcBuffer_Acquire(payload);
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcLogEntry, PARCLogEntry);
+
+parcObject_ImplementRelease(parcLogEntry, PARCLogEntry);
+
+PARCBuffer *
+parcLogEntry_GetPayload(const PARCLogEntry *instance)
+{
+ return instance->payload;
+}
+
+const struct timeval *
+parcLogEntry_GetTimeStamp(const PARCLogEntry *instance)
+{
+ return &instance->timeStamp;
+}
+
+PARCLogLevel
+parcLogEntry_GetLevel(const PARCLogEntry *instance)
+{
+ return instance->level;
+}
+
+int
+parcLogEntry_GetVersion(const PARCLogEntry *instance)
+{
+ return instance->version;
+}
+
+const char *
+parcLogEntry_GetHostName(const PARCLogEntry *instance)
+{
+ return instance->hostName;
+}
+
+const char *
+parcLogEntry_GetApplicationName(const PARCLogEntry *instance)
+{
+ return instance->applicationName;
+}
+
+const char *
+parcLogEntry_GetProcessName(const PARCLogEntry *instance)
+{
+ return instance->processName;
+}
+
+uint64_t
+parcLogEntry_GetMessageId(const PARCLogEntry *instance)
+{
+ return instance->messageId;
+}
+
+char *
+parcLogEntry_ToString(const PARCLogEntry *entry)
+{
+ return _toString(entry);
+}
diff --git a/libparc/parc/logging/parc_LogEntry.h b/libparc/parc/logging/parc_LogEntry.h
new file mode 100755
index 00000000..90f6c493
--- /dev/null
+++ b/libparc/parc/logging/parc_LogEntry.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 parc_LogEntry.h
+ * @brief Basic Log Entry implementation
+ *
+ * PARCLogEntry instances contain logging information in a single message.
+ *
+ * Each instance contains:
+ * * A log level (see PARCLogLevel).
+ * * An integer version number denoting the version of the syslog protocol specification (1).
+ * * A timestamp representable as an RFC 3339 Timestamp.
+ * * A hostname identifing the machine that originally sent the message.
+ * * An application name identifing the device or application that originated the message.
+ * * A process identifier having specific meaning,
+ * except that a change in the value indicates there has been a discontinuity in a series of
+ * otherwise linear PARCLogEntry instances.
+ * * A message identifier as a string without further semantics other than identifing the type of message.
+ *
+ */
+#ifndef PARC_Library_parc_LogEntry_h
+#define PARC_Library_parc_LogEntry_h
+
+#include <stdlib.h>
+
+#include <parc/algol/parc_Buffer.h>
+#include <sys/time.h>
+
+struct PARCLogEntry;
+typedef struct PARCLogEntry PARCLogEntry;
+
+#include <parc/logging/parc_LogLevel.h>
+
+/**
+ * Create a PARCLogEntry instance.
+ *
+ * @param [in] level A log level (see PARCLogLevel).
+ * * An integer version number denoting the version of the syslog protocol specification (1).
+ * @param [in] timeStamp The timestamp for the PARCLogEntry.
+ * @param [in] hostName The hostname identifing the machine that originally sent the message.
+ * @param [in] applicationName The application name identifing the device or application that originated the message.
+ * @param [in] processId An identifier having no specific meaning,
+ * except that a change in the value indicates there has been a discontinuity in a series of
+ * otherwise linear PARCLogEntry instances.
+ * @param [in] messageId A message identifier for the type of message.
+ * @param [in] payload The message component of the LogEntry.
+ *
+ * @return non-NULL A valid instance of PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCLogEntry *parcLogEntry_Create(PARCLogLevel level,
+ const char *hostName,
+ const char *applicationName,
+ const char *processId,
+ const uint64_t messageId,
+ const struct timeval timeStamp,
+ PARCBuffer *payload);
+
+/**
+ * Increase the number of references to a `PARCLogEntry` instance.
+ *
+ * Note that new `PARCLogEntry` is not created,
+ * only that the given `PARCLogEntry` reference count is incremented.
+ * Discard the reference by invoking `parcLogEntry_Release`.
+ *
+ * @param [in] instance A pointer to a `PARCLogEntry` instance.
+ *
+ * @return The input `PARCLogEntry` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogEntry *x = parcLogEntry_Create(...);
+ *
+ * PARCLogEntry *x_2 = parcLogEntry_Acquire(x);
+ *
+ * parcLogEntry_Release(&x);
+ * parcLogEntry_Release(&x_2);
+ * }
+ * @endcode
+ */
+PARCLogEntry *parcLogEntry_Acquire(const PARCLogEntry *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] entryPtr A pointer to a pointer to a PARCLogEntry. The parameter is set to zero.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogEntry *entry = parcLogEntry_Create(...)
+ *
+ * parcLogEntry_Release(&entry);
+ * }
+ * @endcode
+ */
+void parcLogEntry_Release(PARCLogEntry **entryPtr);
+
+/**
+ * Produce a null-terminated string representation of the specified instance.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] entry A pointer to the 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
+ * {
+ * PARCLogEntry *entry = parcLogEntry_Create(...)
+ *
+ * char *string = parcLogEntry_ToString(entry);
+ * printf("%s\n", string);
+ * parcMemory_Deallocate(&string);
+ *
+ * parcLogEntry_Release(&entry);
+ * }
+ * @endcode
+ *
+ */
+char *parcLogEntry_ToString(const PARCLogEntry *entry);
+
+/**
+ * Get the payload of the specified PARCLogEntry.
+ *
+ * @param [in] instance A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return A pointer to the payload of the PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *parcLogEntry_GetPayload(const PARCLogEntry *instance);
+
+/**
+ * Get the timestamp of the specified PARCLogEntry.
+ *
+ * @param [in] instance A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return A pointer to the struct timeval of the PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const struct timeval *parcLogEntry_GetTimeStamp(const PARCLogEntry *instance);
+
+/**
+ * Get the PARCLogLevel of the given PARCLogEntry.
+ *
+ * @param [in] instance A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return The PARCLogLevel of the given PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCLogLevel parcLogEntry_GetLevel(const PARCLogEntry *instance);
+
+/**
+ * Get the PARCLogLevel of the given PARCLogEntry.
+ *
+ * @param [in] instance A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return The version number of the given PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+int parcLogEntry_GetVersion(const PARCLogEntry *instance);
+
+/**
+ * Get the host-name of the given PARCLogEntry.
+ *
+ * @param [in] instance A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return The application name of the given PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+const char *parcLogEntry_GetHostName(const PARCLogEntry *instance);
+
+/**
+ * Get the application-name of the given PARCLogEntry.
+ *
+ * @param [in] instance A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return The application name of the given PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+const char *parcLogEntry_GetApplicationName(const PARCLogEntry *instance);
+
+/**
+ * Get the process-id of the given PARCLogEntry.
+ *
+ * @param [in] instance A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return The process-id of the given PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+const char *parcLogEntry_GetProcessName(const PARCLogEntry *instance);
+
+/**
+ * Get the message-id of the given PARCLogEntry.
+ *
+ * @param [in] instance A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return The message-id of the given PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+uint64_t parcLogEntry_GetMessageId(const PARCLogEntry *instance);
+
+#endif
diff --git a/libparc/parc/logging/parc_LogFormatSyslog.c b/libparc/parc/logging/parc_LogFormatSyslog.c
new file mode 100755
index 00000000..2b3e7e9c
--- /dev/null
+++ b/libparc/parc/logging/parc_LogFormatSyslog.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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <inttypes.h>
+
+#include <parc/logging/parc_LogFormatSyslog.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Time.h>
+
+/*
+ * RFC 5424
+ *
+ * SYSLOG-MSG = HEADER SP STRUCTURED-DATA [SP MSG]
+ *
+ * HEADER = PRI VERSION SP TIMESTAMP SP HOSTNAME SP APP-NAME SP PROCID SP MSGID
+ * PRI = "<" PRIVAL ">"
+ * PRIVAL = 1*3DIGIT ; range 0 .. 191
+ * VERSION = NONZERO-DIGIT 0*2DIGIT
+ * HOSTNAME = NILVALUE / 1*255PRINTUSASCII
+ *
+ * APP-NAME = NILVALUE / 1*48PRINTUSASCII
+ * PROCID = NILVALUE / 1*128PRINTUSASCII
+ * MSGID = NILVALUE / 1*32PRINTUSASCII
+ *
+ * TIMESTAMP = NILVALUE / FULL-DATE "T" FULL-TIME
+ * FULL-DATE = DATE-FULLYEAR "-" DATE-MONTH "-" DATE-MDAY
+ * DATE-FULLYEAR = 4DIGIT
+ * DATE-MONTH = 2DIGIT ; 01-12
+ * DATE-MDAY = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on month/year
+ * FULL-TIME = PARTIAL-TIME TIME-OFFSET
+ * PARTIAL-TIME = TIME-HOUR ":" TIME-MINUTE ":" TIME-SECOND
+ * [TIME-SECFRAC]
+ * TIME-HOUR = 2DIGIT ; 00-23
+ * TIME-MINUTE = 2DIGIT ; 00-59
+ * TIME-SECOND = 2DIGIT ; 00-59
+ * TIME-SECFRAC = "." 1*6DIGIT
+ * TIME-OFFSET = "Z" / TIME-NUMOFFSET
+ * TIME-NUMOFFSET = ("+" / "-") TIME-HOUR ":" TIME-MINUTE
+ *
+ *
+ * STRUCTURED-DATA = NILVALUE / 1*SD-ELEMENT
+ * SD-ELEMENT = "[" SD-ID *(SP SD-PARAM) "]"
+ * SD-PARAM = PARAM-NAME "=" %d34 PARAM-VALUE %d34
+ * SD-ID = SD-NAME
+ * PARAM-NAME = SD-NAME
+ * PARAM-VALUE = UTF-8-STRING ; characters '"', '\' and ']' MUST be escaped.
+ * SD-NAME = 1*32PRINTUSASCII ; except '=', SP, ']', %d34 (")
+ *
+ * MSG = MSG-ANY / MSG-UTF8
+ * MSG-ANY = *OCTET ; not starting with BOM
+ * MSG-UTF8 = BOM UTF-8-STRING
+ * BOM = %xEF.BB.BF
+ *
+ *
+ * UTF-8-STRING = *OCTET ; UTF-8 string as specified in RFC 3629
+ *
+ * OCTET = %d00-255
+ * SP = %d32
+ * PRINTUSASCII = %d33-126
+ * NONZERO-DIGIT = %d49-57
+ * DIGIT = %d48 / NONZERO-DIGIT
+ * NILVALUE = "-"
+ */
+/**
+ * Create a PARCBuffer containing the PARCLogEntry formatted according to RFC 5424 section 6.
+ *
+ * The returned PARCBuffer's position is set to the start of the formatted data and continues to the limit.
+ *
+ * @param [in] entry A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return non-NULL A pointer to a PARCBuffer containing the formatted PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see parcLogEntry_ToString
+ */
+PARCBuffer *
+parcLogFormatSyslog_FormatEntry(const PARCLogEntry *entry)
+{
+ PARCBuffer *payload = parcLogEntry_GetPayload(entry);
+
+ char theTime[64];
+ parcTime_TimevalAsRFC3339(parcLogEntry_GetTimeStamp(entry), theTime);
+
+ PARCBufferComposer *composer = parcBufferComposer_Allocate(128);
+
+ parcBufferComposer_Format(composer, "<%s> %d ",
+ parcLogLevel_ToString(parcLogEntry_GetLevel(entry)), parcLogEntry_GetVersion(entry));
+ parcBufferComposer_PutStrings(composer,
+ theTime, " ",
+ parcLogEntry_GetHostName(entry), " ",
+ parcLogEntry_GetApplicationName(entry), " ",
+ parcLogEntry_GetProcessName(entry), " ", NULL);
+
+ parcBufferComposer_Format(composer, "%" PRId64 " [ ", parcLogEntry_GetMessageId(entry));
+ parcBufferComposer_PutBuffer(composer, payload);
+ parcBufferComposer_PutStrings(composer, " ]\n", NULL);
+ PARCBuffer *result = parcBuffer_Flip(parcBuffer_Acquire(parcBufferComposer_GetBuffer(composer)));
+
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
diff --git a/libparc/parc/logging/parc_LogFormatSyslog.h b/libparc/parc/logging/parc_LogFormatSyslog.h
new file mode 100755
index 00000000..3ace4e7b
--- /dev/null
+++ b/libparc/parc/logging/parc_LogFormatSyslog.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 parc_LogFormatSyslog.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef __PARC_Library__parc_LogFormatSyslog__
+#define __PARC_Library__parc_LogFormatSyslog__
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/logging/parc_LogEntry.h>
+
+PARCBuffer *parcLogFormatSyslog_FormatEntry(const PARCLogEntry *entry);
+
+#endif /* defined(__PARC_Library__parc_LogFormatSyslog__) */
diff --git a/libparc/parc/logging/parc_LogFormatText.c b/libparc/parc/logging/parc_LogFormatText.c
new file mode 100755
index 00000000..7497967b
--- /dev/null
+++ b/libparc/parc/logging/parc_LogFormatText.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 <inttypes.h>
+
+#include <parc/logging/parc_LogFormatText.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Time.h>
+
+PARCBuffer *
+parcLogFormatText_FormatEntry(const PARCLogEntry *entry)
+{
+ PARCBuffer *payload = parcLogEntry_GetPayload(entry);
+
+ char theTime[64];
+ parcTime_TimevalAsRFC3339(parcLogEntry_GetTimeStamp(entry), theTime);
+
+ PARCBufferComposer *composer = parcBufferComposer_Allocate(128);
+
+ parcBufferComposer_PutStrings(composer,
+ theTime, " ",
+ parcLogLevel_ToString(parcLogEntry_GetLevel(entry)), " ",
+ parcLogEntry_GetHostName(entry), " ",
+ parcLogEntry_GetApplicationName(entry), " ",
+ parcLogEntry_GetProcessName(entry), " ", NULL);
+
+ parcBufferComposer_Format(composer, "%" PRId64 " [ ", parcLogEntry_GetMessageId(entry));
+ parcBufferComposer_PutBuffer(composer, payload);
+ parcBufferComposer_PutStrings(composer, " ]\n", NULL);
+ PARCBuffer *result = parcBuffer_Flip(parcBuffer_Acquire(parcBufferComposer_GetBuffer(composer)));
+
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
diff --git a/libparc/parc/logging/parc_LogFormatText.h b/libparc/parc/logging/parc_LogFormatText.h
new file mode 100755
index 00000000..b4bb5b1f
--- /dev/null
+++ b/libparc/parc/logging/parc_LogFormatText.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 parc_LogFormatText.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef __PARC_Library__parc_LogFormatText__
+#define __PARC_Library__parc_LogFormatText__
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/logging/parc_LogEntry.h>
+
+PARCBuffer *parcLogFormatText_FormatEntry(const PARCLogEntry *entry);
+
+#endif /* defined(__PARC_Library__parc_LogFormatText__) */
diff --git a/libparc/parc/logging/parc_LogLevel.c b/libparc/parc/logging/parc_LogLevel.c
new file mode 100755
index 00000000..62d07072
--- /dev/null
+++ b/libparc/parc/logging/parc_LogLevel.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <parc/logging/parc_LogLevel.h>
+
+const PARCLogLevel PARCLogLevel_Off = 0;
+
+const PARCLogLevel PARCLogLevel_All = 255;
+
+const PARCLogLevel PARCLogLevel_Emergency = 1;
+
+const PARCLogLevel PARCLogLevel_Alert = 2;
+
+const PARCLogLevel PARCLogLevel_Critical = 3;
+
+const PARCLogLevel PARCLogLevel_Error = 4;
+
+const PARCLogLevel PARCLogLevel_Warning = 5;
+
+const PARCLogLevel PARCLogLevel_Notice = 6;
+
+const PARCLogLevel PARCLogLevel_Info = 7;
+
+const PARCLogLevel PARCLogLevel_Debug = 8;
+
+static char *levelToString[] = {
+ "Off",
+ "Emergency",
+ "Alert",
+ "Critical",
+ "Error",
+ "Warning",
+ "Notice",
+ "Info",
+ "Debug",
+ NULL
+};
+
+//int
+//parcLogLevel_Compare(const PARCLogLevel levelA, const PARCLogLevel levelB)
+//{
+// return levelA - levelB;
+//}
+
+int
+parcLogLevel_Equals(const PARCLogLevel levelA, const PARCLogLevel levelB)
+{
+ return levelA == levelB;
+}
+
+
+PARCLogLevel
+parcLogLevel_FromString(const char *levelAsString)
+{
+ PARCLogLevel result = PARCLogLevel_All;
+ for (size_t i = 0; levelToString[i] != NULL; i++) {
+ if (strcasecmp(levelAsString, levelToString[i]) == 0) {
+ result = i;
+ }
+ }
+
+ return result;
+}
+
+const char *
+parcLogLevel_ToString(const PARCLogLevel level)
+{
+ char *result = "All";
+ if (level <= PARCLogLevel_Debug) {
+ result = levelToString[level];
+ }
+ return result;
+}
diff --git a/libparc/parc/logging/parc_LogLevel.h b/libparc/parc/logging/parc_LogLevel.h
new file mode 100755
index 00000000..4540924e
--- /dev/null
+++ b/libparc/parc/logging/parc_LogLevel.h
@@ -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.
+ */
+
+/**
+ * @file parc_LogLevel.h
+ * @brief Logging levels for PARCLog
+ *
+ * A PARCLogLevel represents both the severity level of a particular PARCLogEntry,
+ * and the threshold of a particular PARCLog instance.
+ *
+ */
+#ifndef PARC_Library_parc_LogLevel_h
+#define PARC_Library_parc_LogLevel_h
+
+typedef unsigned char PARCLogLevel;
+
+/** OFF is a special level that can be used to turn off logging. */
+extern const PARCLogLevel PARCLogLevel_Off;
+
+/** ALL indicates that all messages should be logged. */
+extern const PARCLogLevel PARCLogLevel_All;
+
+/** PARCLogLevel_Emergency is a message level indicating the system is unusable. */
+extern const PARCLogLevel PARCLogLevel_Emergency;
+
+/** PARCLogLevel_Alert is a message level indicating action must be taken immediately to ensure correctness. */
+extern const PARCLogLevel PARCLogLevel_Alert;
+
+/** PARCLogLevel_Critical is a message level for critical conditions. */
+extern const PARCLogLevel PARCLogLevel_Critical;
+
+/** PARCLogLevel_Error is a message level reporting error conditions. */
+extern const PARCLogLevel PARCLogLevel_Error;
+
+/** PARCLogLevel_Warning indicates a fairly detailed tracing message. */
+extern const PARCLogLevel PARCLogLevel_Warning;
+
+/** FINEST indicates a normal but significant condition. */
+extern const PARCLogLevel PARCLogLevel_Notice;
+
+/** INFO is a message level for informational messages. */
+extern const PARCLogLevel PARCLogLevel_Info;
+
+/** INFO is a message level for debug-level messages. */
+extern const PARCLogLevel PARCLogLevel_Debug;
+
+/**
+ * Compare `PARCLogLevel` instances @p levelA and @p levelA for order.
+ *
+ * @param [in] levelA An instance of PARCLogLevel.
+ * @param [in] levelB An instance of PARCLogLevel.
+ *
+ * @return < 0 levelA is less than levelB
+ * @return == 0 levelA is equal to levelB
+ * @return > 0 levelA is greater than levelB
+ *
+ * Example:
+ * @code
+ * {
+ * int comparison = parcLogLevel_Compare(PARCLogLevel_Notice, PARCLogLevel_Notice);
+ * }
+ * @endcode
+ */
+#define parcLogLevel_Compare(_levelA_, _levelB_) (_levelA_ - _levelB_)
+//int parcLogLevel_Compare(const PARCLogLevel levelA, const PARCLogLevel levelB);
+
+/**
+ * Determine if two instances of PARCLogLevel are equal.
+ *
+ * @param [in] levelA An instance of PARCLogLevel.
+ * @param [in] levelB An instance of PARCLogLevel.
+ *
+ * @return true The instances are equal.
+ * @return false The instances are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * bool equal = parcLogLevel_Equals(PARCLogLevel_Notice, PARCLogLevel_Notice);
+ * }
+ * @endcode
+ */
+int parcLogLevel_Equals(const PARCLogLevel levelA, const PARCLogLevel levelB);
+
+/**
+ * Get the string representation of the PARCLogLevel;
+ *
+ * @param [in] level A valid PARCLogLevel
+ *
+ * @return A pointer to a constant, nul-terminated C string.
+ *
+ * Example:
+ * @code
+ * {
+ * const char * logLevelString = parcLogLevel_ToString(PARCLogLevel_Emergency);
+ * }
+ * @endcode
+ */
+const char *parcLogLevel_ToString(const PARCLogLevel level);
+
+/**
+ * Given a string representation of a logging level, return the corresponding PARCLogLevel value.
+ *
+ * The string is case insensitive.
+ *
+ * Unknown or uninterpretable strings return PARCLogLevel_All.
+ *
+ * @param [in] levelAsString A nul-terminated C string representation of the logging level.
+ *
+ * @return A valid PARCLogLevel.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogLevel level = parcLogLevel_FromString("Emergency");
+ * }
+ * @endcode
+ */
+PARCLogLevel parcLogLevel_FromString(const char *levelAsString);
+#endif
diff --git a/libparc/parc/logging/parc_LogManager.c b/libparc/parc/logging/parc_LogManager.c
new file mode 100755
index 00000000..28f24d07
--- /dev/null
+++ b/libparc/parc/logging/parc_LogManager.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 <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/logging/parc_LogManager.h>
+
+struct PARCLogManager {
+ void *thisIsntFinishedYet;
+};
+
+#if 0
+static void
+_parcLogManager_Destroy(PARCLogManager **instancePtr)
+{
+ //PARCLogManager *instance = *instancePtr;
+}
+#endif
+
+PARCLogManager *
+parcLogManager_Create(void)
+{
+ return NULL;
+}
+
+PARCLogManager *
+parcLogManager_Acquire(const PARCLogManager *instance)
+{
+ return parcObject_Acquire(instance);
+}
+
+void
+parcLogManager_Release(PARCLogManager **instancePtr)
+{
+ parcObject_Release((void **) instancePtr);
+}
diff --git a/libparc/parc/logging/parc_LogManager.h b/libparc/parc/logging/parc_LogManager.h
new file mode 100755
index 00000000..ce50c60b
--- /dev/null
+++ b/libparc/parc/logging/parc_LogManager.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 parc_LogManager.h
+ * @brief <#Brief Description#>
+ *
+ */
+#ifndef PARC_Library_parc_LogManager_h
+#define PARC_Library_parc_LogManager_h
+
+struct PARCLogManager;
+typedef struct PARCLogManager PARCLogManager;
+
+/**
+ * Create a new PARCLogManager
+ *
+ * @return non-NULL A pointer to a valid PARCLogManager
+ * @return NULL Out of memory.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogManager *manager = parcLogManager_Create();
+ *
+ * parcLogManager_Release(&manager);
+ * }
+ * @endcode
+ */
+PARCLogManager *parcLogManager_Create(void);
+
+/**
+ * Increase the number of references to a `PARCLogManager` instance.
+ *
+ * Note that new `PARCLogManager` is not created,
+ * only that the given `PARCLogManager` reference count is incremented.
+ * Discard the reference by invoking `parcLogManager_Release`.
+ *
+ * @param [in] instance A pointer to a `PARCLogManager` instance.
+ *
+ * @return The input `PARCLogManager` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogManager *manager = parcLogManager_Create();
+ *
+ * PARCLogReporter *x_2 = parcLogManager_Acquire(reporter);
+ *
+ * parcLogManager_Release(&manager);
+ * parcLogManager_Release(&x_2);
+ * }
+ * @endcode
+ */
+PARCLogManager *parcLogManager_Acquire(const PARCLogManager *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] instancePtr A pointer to a pointer to a `PARCLogManager`. The parameter is set to zero.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogManager *manager = parcLogManager_Create();
+ *
+ * parcLogManager_Release(&manager);
+ * }
+ * @endcode
+ */
+void parcLogManager_Release(PARCLogManager **instancePtr);
+#endif
diff --git a/libparc/parc/logging/parc_LogReporter.c b/libparc/parc/logging/parc_LogReporter.c
new file mode 100755
index 00000000..a06f360a
--- /dev/null
+++ b/libparc/parc/logging/parc_LogReporter.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <parc/logging/parc_LogReporter.h>
+#include <parc/algol/parc_Object.h>
+
+struct PARCLogReporter {
+ PARCLogReporter *(*acquire)(const PARCLogReporter *);
+ void (*release)(PARCLogReporter **);
+ void (*report)(PARCLogReporter *, const PARCLogEntry *);
+
+ PARCObject *privateObject;
+};
+
+static void
+_parcLogReporter_Destroy(PARCLogReporter **reporterPtr __attribute__((unused)))
+{
+ PARCLogReporter *result = *reporterPtr;
+ if (result->privateObject != NULL) {
+ parcObject_Release(&result->privateObject);
+ }
+}
+
+parcObject_ExtendPARCObject(PARCLogReporter, _parcLogReporter_Destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCLogReporter *
+parcLogReporter_Create(PARCLogReporter *(*acquire)(const PARCLogReporter *),
+ void (*release)(PARCLogReporter **),
+ void (*report)(PARCLogReporter *, const PARCLogEntry *),
+ void *privateObject)
+{
+ PARCLogReporter *result = parcObject_CreateInstance(PARCLogReporter);
+ result->acquire = acquire;
+ result->release = release;
+ result->report = report;
+ result->privateObject = privateObject;
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcLogReporter, PARCLogReporter);
+
+parcObject_ImplementRelease(parcLogReporter, PARCLogReporter);
+
+void
+parcLogReporter_Report(PARCLogReporter *reporter, const PARCLogEntry *report)
+{
+ reporter->report(reporter, report);
+}
+
+void *
+parcLogReporter_GetPrivateObject(const PARCLogReporter *reporter)
+{
+ return reporter->privateObject;
+}
diff --git a/libparc/parc/logging/parc_LogReporter.h b/libparc/parc/logging/parc_LogReporter.h
new file mode 100755
index 00000000..65496f55
--- /dev/null
+++ b/libparc/parc/logging/parc_LogReporter.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 parc_LogReporter.h
+ * @brief An abstract representation of a PARC Log Reporter.
+ *
+ */
+#ifndef PARC_Library_parc_LogReporter_h
+#define PARC_Library_parc_LogReporter_h
+
+#include <parc/logging/parc_LogEntry.h>
+
+typedef void (PARCLogReporterAcquire)(void *reporter);
+
+/**
+ * A Function that performs the final cleanup and resource deallocation when
+ * a PARCLogReporter is no longer needed.
+ */
+typedef void (PARCLogReporterRelease)(void **reporterP);
+
+/**
+ */
+typedef void (PARCLogReporterReport)(const PARCLogEntry *reporter);
+
+struct PARCLogReporter;
+typedef struct PARCLogReporter PARCLogReporter;
+
+/**
+ * Create a new instance of `PARCLogReporter` using the given the functions specified.
+ *
+ * @param [in] acquire A pointer to a function that performs the Aquire contract.
+ * @param [in] release A pointer to a function that performs the Release contract.
+ * @param [in] report A pointer to a function that performs the 'report' function.
+ * @param [in] privateObject A pointer to a PARCObject that is supplied to the report function when invoked, or NULL.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a valid `PARCLogReporter` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogReporter *result = parcLogReporter_Create(&parcLogReporterFile_Acquire,
+ * parcLogReporterFile_Release,
+ * parcLogReporterFile_Report,
+ * parcOutputStream_Acquire(output));
+ * return result;
+ * }
+ * @endcode
+ */
+PARCLogReporter *parcLogReporter_Create(PARCLogReporter *(*acquire)(const PARCLogReporter *),
+ void (*release)(PARCLogReporter **),
+ void (*report)(PARCLogReporter *, const PARCLogEntry *),
+ void *privateObject);
+
+/**
+ * Increase the number of references to a `PARCLogReporter` instance.
+ *
+ * Note that new `PARCLogReporter` is not created,
+ * only that the given `PARCLogReporter` reference count is incremented.
+ * Discard the reference by invoking `parcLogReporter_Release`.
+ *
+ * @param [in] instance A pointer to a `PARCLogReporter` instance.
+ *
+ * @return The input `PARCLogReporter` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogReporter *reporter = parcLogReporter_Create(&parcLogReporterFile_Acquire,
+ * parcLogReporterFile_Release,
+ * parcLogReporterFile_Report,
+ * parcOutputStream_Acquire(output));
+ *
+ * PARCLogReporter *x_2 = parcLogReporter_Acquire(reporter);
+ *
+ * parcLogReporter_Release(&reporter);
+ * parcLogReporter_Release(&x_2);
+ * }
+ * @endcode
+ */
+PARCLogReporter *parcLogReporter_Acquire(const PARCLogReporter *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] instancePtr A pointer to a pointer to a `PARCLogReporter`. The parameter is set to zero.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogReporter *reporter = parcLogReporter_Create(&parcLogReporterFile_Acquire,
+ * parcLogReporterFile_Release,
+ * parcLogReporterFile_Report,
+ * parcOutputStream_Acquire(output));
+ *
+ * parcLogReporter_Release(&reporter);
+ * }
+ * @endcode
+ */
+void parcLogReporter_Release(PARCLogReporter **instancePtr);
+
+/**
+ * Report the given PARCLogEntry
+ *
+ * @param [in] reporter A pointer to a valid PARCLogReporter instance.
+ * @param [in] entry A pointer to a valid PARCLogEntry instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcLogReporter_Report(PARCLogReporter *reporter, const PARCLogEntry *entry);
+
+/**
+ * Get the private PARCObject supplied when the PARCLogReporter was created.
+ *
+ * @param [in] reporter A valid PARCLogReporter instance.
+ *
+ * @return A same pointer supplied when the PARCLogReporter was created.
+ *
+ */
+void *parcLogReporter_GetPrivateObject(const PARCLogReporter *reporter);
+
+#endif
diff --git a/libparc/parc/logging/parc_LogReporterFile.c b/libparc/parc/logging/parc_LogReporterFile.c
new file mode 100755
index 00000000..d9bd4986
--- /dev/null
+++ b/libparc/parc/logging/parc_LogReporterFile.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 <inttypes.h>
+
+#include <parc/logging/parc_LogReporterFile.h>
+#include <parc/logging/parc_LogFormatSyslog.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Time.h>
+
+#include <parc/algol/parc_FileOutputStream.h>
+
+PARCLogReporter *
+parcLogReporterFile_Create(PARCOutputStream *output)
+{
+ PARCLogReporter *result = parcLogReporter_Create(&parcLogReporterFile_Acquire,
+ parcLogReporterFile_Release,
+ parcLogReporterFile_Report,
+ parcOutputStream_Acquire(output));
+ return result;
+}
+
+PARCLogReporter *
+parcLogReporterFile_Acquire(const PARCLogReporter *reporter)
+{
+ return parcObject_Acquire(reporter);
+}
+
+void
+parcLogReporterFile_Release(PARCLogReporter **reporterP)
+{
+ parcObject_Release((void **) reporterP);
+}
+
+void
+parcLogReporterFile_Report(PARCLogReporter *reporter, const PARCLogEntry *entry)
+{
+ PARCOutputStream *output = parcLogReporter_GetPrivateObject(reporter);
+
+ PARCBuffer *formatted = parcLogFormatSyslog_FormatEntry(entry);
+ parcOutputStream_Write(output, formatted);
+ parcBuffer_Release(&formatted);
+}
diff --git a/libparc/parc/logging/parc_LogReporterFile.h b/libparc/parc/logging/parc_LogReporterFile.h
new file mode 100755
index 00000000..19bbae5d
--- /dev/null
+++ b/libparc/parc/logging/parc_LogReporterFile.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 parc_LogReporterFile.h
+ * @brief <#Brief Description#>
+ *
+ */
+#ifndef __PARC_Library__parc_LogReporterFile__
+#define __PARC_Library__parc_LogReporterFile__
+
+#include <parc/logging/parc_LogReporter.h>
+#include <parc/algol/parc_OutputStream.h>
+
+/**
+ * Create a new instance of `PARCLogReporter` using the given {@link PARCOutputStream}.
+ *
+ * @param [in] output A pointer to a valid `PARCOutputStream` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a valid `PARCLogReporter` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ * PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ * parcFileOutputStream_Release(&fileOutput);
+ *
+ * PARCLogReporter *reporter = parcLogReporterFile_Create(out);
+ * parcOutputStream_Release(&out);
+ *
+ * parcLogReporter_Release(&reporter);
+ * }
+ * <#example#>
+ * @endcode
+ */
+PARCLogReporter *parcLogReporterFile_Create(PARCOutputStream *output);
+
+/**
+ * Increase the number of references to a `PARCLogReporter` instance.
+ *
+ * Note that new `PARCLogReporter` is not created,
+ * only that the given `PARCLogReporter` reference count is incremented.
+ * Discard the reference by invoking `parcLogEntry_Release`.
+ *
+ * @param [in] instance A pointer to a `PARCLogReporter` instance.
+ *
+ * @return The input `PARCLogReporter` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogReporter *x = parcLogReporterFile_Create(...);
+ *
+ * PARCLogReporter *x_2 = parcLogReporterFile_Acquire(x);
+ *
+ * parcLogReporterFile_Release(&x);
+ * parcLogReporterFile_Release(&x_2);
+ * }
+ * @endcode
+ */
+PARCLogReporter *parcLogReporterFile_Acquire(const PARCLogReporter *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] reporterP A pointer to a PARCLogReporter instance pointer, which will be set to zero on return.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogReporter *x = parcLogReporterFile_Create(...);
+ *
+ * parcLogReporterFile_Release(&x);
+ * }
+ * @endcode
+ */
+void parcLogReporterFile_Release(PARCLogReporter **reporterP);
+
+/**
+ * Report the given PARCLogEntry
+ *
+ * @param [in] reporter A pointer to a valid PARCLogReporter instance.
+ * @param [in] entry A pointer to a valid PARCLogEntry instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcLogReporterFile_Report(PARCLogReporter *reporter, const PARCLogEntry *entry);
+#endif /* defined(__PARC_Library__parc_LogReporterFile__) */
diff --git a/libparc/parc/logging/parc_LogReporterTextStdout.c b/libparc/parc/logging/parc_LogReporterTextStdout.c
new file mode 100755
index 00000000..86d5190e
--- /dev/null
+++ b/libparc/parc/logging/parc_LogReporterTextStdout.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.
+ */
+
+/**
+ */
+#include <config.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_OutputStream.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Time.h>
+
+#include <parc/logging/parc_LogReporterTextStdout.h>
+#include <parc/logging/parc_LogFormatText.h>
+
+PARCLogReporter *
+parcLogReporterTextStdout_Create(void)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *result = parcLogReporter_Create(&parcLogReporterTextStdout_Acquire,
+ parcLogReporterTextStdout_Release,
+ parcLogReporterTextStdout_Report,
+ parcOutputStream_Acquire(out));
+ parcOutputStream_Release(&out);
+ return result;
+}
+
+PARCLogReporter *
+parcLogReporterTextStdout_Acquire(const PARCLogReporter *instance)
+{
+ return parcObject_Acquire(instance);
+}
+
+void
+parcLogReporterTextStdout_Release(PARCLogReporter **reporterP)
+{
+ parcObject_Release((void **) reporterP);
+}
+
+void
+parcLogReporterTextStdout_Report(PARCLogReporter *reporter, const PARCLogEntry *entry)
+{
+ PARCOutputStream *output = parcLogReporter_GetPrivateObject(reporter);
+
+ PARCBuffer *formatted = parcLogFormatText_FormatEntry(entry);
+ parcOutputStream_Write(output, formatted);
+ parcBuffer_Release(&formatted);
+}
diff --git a/libparc/parc/logging/parc_LogReporterTextStdout.h b/libparc/parc/logging/parc_LogReporterTextStdout.h
new file mode 100755
index 00000000..4365330e
--- /dev/null
+++ b/libparc/parc/logging/parc_LogReporterTextStdout.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 parc_LogReporterTextStdout.h
+ * @brief A simple log reporter using plain text formatting to standard output.
+ *
+ */
+#ifndef PARC_Library_parc_LogReporterTextStdout_h
+#define PARC_Library_parc_LogReporterTextStdout_h
+
+#include <parc/logging/parc_LogReporter.h>
+
+/**
+ * Create a new instance of `PARCLogReporter` using standard output.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a valid `PARCLogReporter` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ *
+ * parcLogReporter_Release(&reporter);
+ * }
+ * <#example#>
+ * @endcode
+ */
+PARCLogReporter *parcLogReporterTextStdout_Create(void);
+
+/**
+ * Increase the number of references to a `PARCLogReporter` instance.
+ *
+ * Note that new `PARCLogReporter` is not created,
+ * only that the given `PARCLogReporter` reference count is incremented.
+ * Discard the reference by invoking `parcLogEntry_Release`.
+ *
+ * @param [in] instance A pointer to a `PARCLogReporter` instance.
+ *
+ * @return The input `PARCLogReporter` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogReporter *x = parcLogReporterTextStdout_Create();
+ *
+ * PARCLogReporter *x_2 = parcLogReporterTextStdout_Acquire(x);
+ *
+ * parcLogReporterTextStdout_Release(&x);
+ * parcLogReporterTextStdout_Release(&x_2);
+ * }
+ * @endcode
+ */
+PARCLogReporter *parcLogReporterTextStdout_Acquire(const PARCLogReporter *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] reporterP A pointer to a PARCLogReporter instance pointer, which will be set to zero on return.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogReporter *x = parcLogReporterTextStdout_Create();
+ *
+ * parcLogReporterTextStdout_Release(&x);
+ * }
+ * @endcode
+ */
+void parcLogReporterTextStdout_Release(PARCLogReporter **reporterP);
+
+/**
+ * Report the given PARCLogEntry
+ *
+ * @param [in] reporter A pointer to a valid PARCLogReporter instance.
+ * @param [in] entry A pointer to a valid PARCLogEntry instance.
+ *
+ * @see parcLogReporter_Report
+ */
+void parcLogReporterTextStdout_Report(PARCLogReporter *reporter, const PARCLogEntry *entry);
+
+#endif
diff --git a/libparc/parc/logging/test/.gitignore b/libparc/parc/logging/test/.gitignore
new file mode 100644
index 00000000..9b66ee0e
--- /dev/null
+++ b/libparc/parc/logging/test/.gitignore
@@ -0,0 +1,12 @@
+*.gcov
+*.gcda
+*.gcno
+*.log
+test_parc_LogEntry
+test_parc_Log
+test_parc_LogReporterFile
+test_parc_LogLevel
+test_parc_LogReporter
+test_parc_LogReporterTextStdout
+test_parc_LogFormatSyslog
+test_parc_LogFormatText
diff --git a/libparc/parc/logging/test/CMakeLists.txt b/libparc/parc/logging/test/CMakeLists.txt
new file mode 100644
index 00000000..060a0ba1
--- /dev/null
+++ b/libparc/parc/logging/test/CMakeLists.txt
@@ -0,0 +1,20 @@
+set(TestsExpectedToPass
+ test_parc_Log
+ test_parc_LogEntry
+ test_parc_LogFormatSyslog
+ test_parc_LogFormatText
+ test_parc_LogLevel
+ test_parc_LogReporter
+ test_parc_LogReporterFile
+ test_parc_LogReporterTextStdout
+ )
+
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
+
diff --git a/libparc/parc/logging/test/test_parc_Log.c b/libparc/parc/logging/test/test_parc_Log.c
new file mode 100644
index 00000000..af9f65a5
--- /dev/null
+++ b/libparc/parc/logging/test/test_parc_Log.c
@@ -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.
+ */
+
+/** *
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Log.c"
+
+#include <parc/logging/parc_LogLevel.h>
+#include <parc/logging/parc_LogReporterFile.h>
+
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+LONGBOW_TEST_RUNNER(test_parc_Log)
+{
+ // 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(CreateDestroy);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_parc_Log)
+{
+ 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_parc_Log)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+uint32_t CreationInitialMemoryOutstanding = 0;
+
+LONGBOW_TEST_FIXTURE(CreateDestroy)
+{
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcLog_Create);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcLog_Create_DefaultValues);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateDestroy)
+{
+ CreationInitialMemoryOutstanding = parcMemory_Outstanding();
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateDestroy)
+{
+ if (parcMemory_Outstanding() != CreationInitialMemoryOutstanding) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("'%s' leaks memory by %u\n",
+ longBowTestCase_GetName(testCase), parcMemory_Outstanding() - CreationInitialMemoryOutstanding);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcLog_Create)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ parcOutputStream_Release(&output);
+
+ PARCLog *log = parcLog_Create("localhost", "test_parc_Log", NULL, reporter);
+ parcLogReporter_Release(&reporter);
+
+ assertTrue(parcLogLevel_Equals(parcLog_GetLevel(log), PARCLogLevel_Off), "Expected initial log level to be OFF");
+
+ parcLog_Release(&log);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcLog_Create_DefaultValues)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ parcOutputStream_Release(&output);
+
+ PARCLog *log = parcLog_Create(NULL, NULL, NULL, reporter);
+ parcLogReporter_Release(&reporter);
+
+ assertTrue(parcLogLevel_Equals(parcLog_GetLevel(log), PARCLogLevel_Off), "Expected initial log level to be OFF");
+
+ parcLog_Release(&log);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Emergency);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Warning);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Alert);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Critical);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Error);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Notice);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Debug);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Info);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Message);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_IsLoggable_True);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_IsLoggable_False);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Emergency_WrongLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Warning_WrongLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Alert_WrongLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Critical_WrongLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Error_WrongLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Notice_WrongLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Debug_WrongLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Info_WrongLevel);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ CreationInitialMemoryOutstanding = parcMemory_Outstanding();
+
+ {
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ parcOutputStream_Release(&output);
+
+ PARCLog *log = parcLog_Create("localhost", "test_parc_Log", NULL, reporter);
+ parcLogReporter_Release(&reporter);
+
+ parcLog_SetLevel(log, PARCLogLevel_All);
+
+ longBowTestCase_SetClipBoardData(testCase, log);
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ {
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_Release(&log);
+ }
+
+ if (parcMemory_Outstanding() != CreationInitialMemoryOutstanding) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("'%s' leaks memory by %u\n",
+ longBowTestCase_GetName(testCase), parcMemory_Outstanding() - CreationInitialMemoryOutstanding);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_IsLoggable_True)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_IsLoggable(log, PARCLogLevel_Alert), "Expected parcLog_IsLoggable to be true.");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_IsLoggable_False)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ assertFalse(parcLog_IsLoggable(log, PARCLogLevel_Alert), "Expected parcLog_IsLoggable to be true.");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Info)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_Info(log, "This is a info message"),
+ "Expected message to be logged successfully");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Warning)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_Warning(log, "This is a warning message"),
+ "Expected message to be logged successfully");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Emergency)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_Emergency(log, "This is an emergency message"),
+ "Expected message to be logged successfully");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Alert)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_Alert(log, "This is a alert message"),
+ "Expected message to be logged successfully");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Critical)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_Critical(log, "This is a critical message"),
+ "Expected message to be logged successfully");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Notice)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_Notice(log, "This is a notice message"),
+ "Expected message to be logged successfully");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Error)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_Error(log, "This is a error message"),
+ "Expected message to be logged successfully");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Debug)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_Debug(log, "This is a debug message"),
+ "Expected message to be logged successfully");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Warning_WrongLevel)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ assertFalse(parcLog_Warning(log, "This is a warning message"),
+ "Expected message to not be logged");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Emergency_WrongLevel)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ // Even if the log level is set to off, you cannot block an emergency message.
+ assertTrue(parcLog_Emergency(log, "This is an emergency message"),
+ "Expected message to not be logged");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Alert_WrongLevel)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ assertFalse(parcLog_Alert(log, "This is a finest message"),
+ "Expected message to not be logged");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Critical_WrongLevel)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ assertFalse(parcLog_Critical(log, "This is a finer message"),
+ "Expected message to not be logged");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Notice_WrongLevel)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ assertFalse(parcLog_Notice(log, "This is a fine message"),
+ "Expected message to not be logged");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Debug_WrongLevel)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ assertFalse(parcLog_Debug(log, "This is a debug message"),
+ "Expected message to not be logged");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Error_WrongLevel)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ assertFalse(parcLog_Error(log, "This is a debug message"),
+ "Expected message to not be logged");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Info_WrongLevel)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ assertFalse(parcLog_Info(log, "This is a debug message"),
+ "Expected message to not be logged");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Message)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Alert);
+
+ assertTrue(parcLog_Message(log, PARCLogLevel_Alert, 0, "This is an alert message"),
+ "Expected message to be logged");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_Log);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/logging/test/test_parc_LogEntry.c b/libparc/parc/logging/test/test_parc_LogEntry.c
new file mode 100644
index 00000000..56a07c0d
--- /dev/null
+++ b/libparc/parc/logging/test/test_parc_LogEntry.c
@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_LogEntry.c"
+
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+#include <pthread.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <parc/logging/parc_LogReporter.h>
+#include <parc/logging/parc_LogReporterTextStdout.h>
+#include <parc/logging/parc_LogFormatText.h>
+
+LONGBOW_TEST_RUNNER(parc_LogEntry)
+{
+ // 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(Creation);
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+
+ LONGBOW_RUN_TEST_FIXTURE(MultiThreaded);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_LogEntry)
+{
+ 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_LogEntry)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Creation)
+{
+ LONGBOW_RUN_TEST_CASE(Creation, parcLogEntry_CreateRelease);
+}
+
+uint32_t CreationInitialMemoryOutstanding = 0;
+
+LONGBOW_TEST_FIXTURE_SETUP(Creation)
+{
+ CreationInitialMemoryOutstanding = parcMemory_Outstanding();
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Creation)
+{
+ if (parcMemory_Outstanding() != CreationInitialMemoryOutstanding) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("'%s' leaks memory by %u\n",
+ longBowTestCase_GetName(testCase), parcMemory_Outstanding() - CreationInitialMemoryOutstanding);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Creation, parcLogEntry_CreateRelease)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 12345, timeStamp, payload);
+ parcBuffer_Release(&payload);
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcLogEntry_Acquire, entry);
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetTimeStamp);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetMessageId);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetApplicationName);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetHostName);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetProcessName);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetVersion);
+}
+
+uint32_t GlobalInitialMemoryOutstanding = 0;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ GlobalInitialMemoryOutstanding = parcMemory_Outstanding();
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcMemory_Outstanding() != GlobalInitialMemoryOutstanding) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("'%s' leaks memory by %u\n",
+ longBowTestCase_GetName(testCase), parcMemory_Outstanding() - GlobalInitialMemoryOutstanding);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_AcquireRelease)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry = parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+ parcBuffer_Release(&payload);
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcLogEntry_Acquire, entry);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_GetBuffer)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry = parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+ PARCBuffer *actual = parcLogEntry_GetPayload(entry);
+
+ assertTrue(payload == actual, "Expected %p, actual %p", (void *) payload, (void *) actual);
+ parcBuffer_Release(&payload);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_GetTimeStamp)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+ const struct timeval *actual = parcLogEntry_GetTimeStamp(entry);
+
+ assertTrue(memcmp(&timeStamp, actual, sizeof(struct timeval)) == 0, "Expected timeStamp to be identical");
+ parcBuffer_Release(&payload);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_GetLevel)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+ const PARCLogLevel actual = parcLogEntry_GetLevel(entry);
+
+ assertTrue(PARCLogLevel_Info == actual, "Expected %d, actual %d", PARCLogLevel_Info, actual);
+ parcBuffer_Release(&payload);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_GetVersion)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+ const PARCLogLevel actual = parcLogEntry_GetVersion(entry);
+
+ assertTrue(_parcLog_Version == actual, "Expected %d, actual %d", _parcLog_Version, actual);
+ parcBuffer_Release(&payload);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_GetHostName)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+ char *expected = "hostname";
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, expected, "applicationname", "processid", 1234, timeStamp, payload);
+ const char *actual = parcLogEntry_GetHostName(entry);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+ parcBuffer_Release(&payload);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_GetApplicationName)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+ char *expected = "applicationname";
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+ const char *actual = parcLogEntry_GetApplicationName(entry);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+ parcBuffer_Release(&payload);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_GetProcessName)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+ char *expected = "processid";
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", expected, 1234, timeStamp, payload);
+ const char *actual = parcLogEntry_GetProcessName(entry);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+ parcBuffer_Release(&payload);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_GetMessageId)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+
+ uint64_t expected = 1234;
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", expected, timeStamp, payload);
+ const uint64_t actual = parcLogEntry_GetMessageId(entry);
+
+ assertTrue(expected == actual, "Expected %" PRId64 " actual %" PRId64 "", expected, actual);
+ parcBuffer_Release(&payload);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_ToString)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+
+ parcBuffer_Release(&payload);
+
+ char *actual = parcLogEntry_ToString(entry);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, _parcLogEntry_Destroy);
+ LONGBOW_RUN_TEST_CASE(Static, _toString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Static, _parcLogEntry_Destroy)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _toString)
+{
+ testUnimplemented("");
+}
+
+// Multi-threaded test
+
+LONGBOW_TEST_FIXTURE(MultiThreaded)
+{
+ LONGBOW_RUN_TEST_CASE(MultiThreaded, fgThreadTest);
+ LONGBOW_RUN_TEST_CASE(MultiThreaded, bgThreadTest);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(MultiThreaded)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(MultiThreaded)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ //parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("'%s' leaks memory by %u allocations\n",
+ longBowTestCase_GetName(testCase), parcMemory_Outstanding() - CreationInitialMemoryOutstanding);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+void *_runInThread(void *threadLabel);
+void *_runInThread_Stripped(void *threadLabel);
+
+static int _loopCount = INT32_MAX;
+
+void *
+_runInThread(void *threadLabel) // Look at _runInThread_Stripped(), below, instead of this one.
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ PARCBuffer *payload = parcBuffer_AllocateCString(threadLabel);
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+
+ PARCLogEntry *entry = parcLogEntry_Create(PARCLogLevel_Info, "hostName", "applicationName", "processName", _loopCount, timeStamp, payload);
+
+ while (_loopCount > 0) {
+ PARCBuffer *buf = parcLogFormatText_FormatEntry(entry);
+
+ parcLogReporterTextStdout_Report(reporter, entry);
+ parcBuffer_Release(&buf);
+
+ _loopCount--;
+
+ usleep(10 * 1000); // yield for a bit to let another thread have at it.
+ }
+
+ parcLogEntry_Release(&entry);
+
+ parcBuffer_Release(&payload);
+ parcLogReporter_Release(&reporter);
+
+ return threadLabel; // Unchanged from what was passed in.
+}
+
+
+void *
+_runInThread_Stripped(void *threadLabel)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString(threadLabel);
+
+ while (_loopCount > 0) {
+ //
+ // The code below taken from parcLogReporterTextStdout_Report(). I stripped it down some.
+ // If you switch the thread's job from _runInThread_Stripped to _runInThread you can run
+ // the original, which shows the same thing.
+ //
+
+ PARCBufferComposer *composer = parcBufferComposer_Allocate(128);
+
+ parcBufferComposer_Format(composer, "%d [ ", _loopCount);
+ parcBufferComposer_PutBuffer(composer, payload);
+ parcBufferComposer_PutStrings(composer, " ]\n", NULL);
+
+ PARCBuffer *result = parcBuffer_Flip(parcBuffer_Acquire(parcBufferComposer_GetBuffer(composer)));
+ parcBufferComposer_Release(&composer);
+
+ char *string = parcBuffer_ToString(result);
+ parcBuffer_Release(&result);
+
+ printf("%s", string);
+
+ parcMemory_Deallocate((void **) &string);
+
+ _loopCount--;
+
+ usleep(10 * 1000); // yield for a bit to let another thread have at it.
+ }
+
+ parcBuffer_Release(&payload);
+
+ return threadLabel; // Unchanged from what was passed in.
+}
+
+
+LONGBOW_TEST_CASE(MultiThreaded, bgThreadTest)
+{
+ int numThreads = 2;
+ pthread_t workerThreads[numThreads];
+ char *threadLabel[numThreads];
+
+ _loopCount = INT32_MAX; // We'll set it to 0 after a second
+ for (int i = 0; i < numThreads; i++) {
+ if (asprintf(&threadLabel[i], "bg thread #%d", i) > 0) {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ pthread_create(&workerThreads[i], &attr, _runInThread_Stripped, threadLabel[i]);
+ }
+ //pthread_create(&workerThreads[i], &attr, _runInThread, threadLabel[i]);
+ }
+
+ sleep(2); // Let the bg threads run
+
+ _loopCount = 0; // tell the bg threads to stop
+
+ for (int i = 0; i < numThreads; i++) {
+ int status = pthread_join(workerThreads[i], NULL);
+ printf("Child %d (out of %d) joined with status %d\n", i, numThreads, status);
+ free(threadLabel[i]);
+ }
+}
+
+LONGBOW_TEST_CASE(MultiThreaded, fgThreadTest)
+{
+ _loopCount = 10;
+ //_runInThread("main thread"); // Run the same logging loop, but in a single thread
+ _runInThread_Stripped("main thread"); // Run the same logging loop, but in a single thread
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_LogEntry);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/logging/test/test_parc_LogFormatSyslog.c b/libparc/parc/logging/test/test_parc_LogFormatSyslog.c
new file mode 100755
index 00000000..b5d1f4b5
--- /dev/null
+++ b/libparc/parc/logging/test/test_parc_LogFormatSyslog.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_LogFormatSyslog.c"
+
+#include <parc/logging/parc_LogEntry.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_LogFormatSyslog)
+{
+ // 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(parc_LogFormatSyslog)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_LogFormatSyslog)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLogFormatSyslog_FormatEntry);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcLogFormatSyslog_FormatEntry)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+
+ PARCBuffer *actual = parcLogFormatSyslog_FormatEntry(entry);
+ assertTrue(parcBuffer_Remaining(actual) > 0, "Expected formatter to return non-zero length buffer");
+ parcLogEntry_Release(&entry);
+ parcBuffer_Release(&actual);
+}
+
+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(parc_LogFormatSyslog);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/logging/test/test_parc_LogFormatText.c b/libparc/parc/logging/test/test_parc_LogFormatText.c
new file mode 100644
index 00000000..0d294d36
--- /dev/null
+++ b/libparc/parc/logging/test/test_parc_LogFormatText.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.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Runner.
+#include "../parc_LogFormatText.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_LogFormatText)
+{
+ // 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(parc_LogFormatText)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_LogFormatText)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLogFormatText_FormatEntry);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcLogFormatText_FormatEntry)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+
+ PARCBuffer *actual = parcLogFormatText_FormatEntry(entry);
+ assertTrue(parcBuffer_Remaining(actual) > 0, "Expected formatter to return non-zero length buffer");
+ parcLogEntry_Release(&entry);
+ parcBuffer_Release(&actual);
+}
+
+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(parc_LogFormatText);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/logging/test/test_parc_LogLevel.c b/libparc/parc/logging/test/test_parc_LogLevel.c
new file mode 100755
index 00000000..ca05cc5c
--- /dev/null
+++ b/libparc/parc/logging/test/test_parc_LogLevel.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_LogLevel.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_LogLevel)
+{
+ // 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(parc_LogLevel)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_LogLevel)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLogLevel_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogLevel_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogLevel_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogLevel_ToString_All);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogLevel_ToString_Off);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogLevel_FromString_Debug);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogLevel_FromString_All);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcLogLevel_Compare)
+{
+ assertTrue(parcLogLevel_Compare(PARCLogLevel_Off, PARCLogLevel_All) < 0, "Expected PARCLogLevel_Off to be less that All");
+}
+
+LONGBOW_TEST_CASE(Global, parcLogLevel_Equals)
+{
+ assertTrue(parcLogLevel_Equals(PARCLogLevel_Emergency, PARCLogLevel_Emergency), "Expected equality");
+ assertFalse(parcLogLevel_Equals(PARCLogLevel_Emergency, PARCLogLevel_Debug), "Expected inequality");
+}
+
+LONGBOW_TEST_CASE(Global, parcLogLevel_ToString)
+{
+ char *expected = "Debug";
+ const char *actual = parcLogLevel_ToString(PARCLogLevel_Debug);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogLevel_ToString_Off)
+{
+ char *expected = "Off";
+ const char *actual = parcLogLevel_ToString(PARCLogLevel_Off);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogLevel_ToString_All)
+{
+ char *expected = "All";
+ const char *actual = parcLogLevel_ToString(PARCLogLevel_All);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogLevel_FromString_Debug)
+{
+ PARCLogLevel expected = PARCLogLevel_Debug;
+ PARCLogLevel actual = parcLogLevel_FromString("DEBUG");
+
+ assertTrue(expected == actual, "Expected '%d', actual '%d'", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogLevel_FromString_All)
+{
+ PARCLogLevel expected = PARCLogLevel_All;
+ PARCLogLevel actual = parcLogLevel_FromString("AlL");
+
+ assertTrue(expected == actual, "Expected '%d', actual '%d'", expected, actual);
+}
+
+
+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(parc_LogLevel);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/logging/test/test_parc_LogReporter.c b/libparc/parc/logging/test/test_parc_LogReporter.c
new file mode 100644
index 00000000..5a9b0baa
--- /dev/null
+++ b/libparc/parc/logging/test/test_parc_LogReporter.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_LogReporter.c"
+
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/logging/parc_LogReporterFile.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_LogReporter)
+{
+ // 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);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_LogReporter)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_LogReporter)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLogReporter_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogReporter_Create_NULLObject);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogReporter_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogReporter_GetPrivateObject);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogReporter_Report);
+}
+
+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 %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcLogReporter_AcquireRelease)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(out);
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcLogReporter_Acquire, reporter);
+
+ parcOutputStream_Release(&out);
+
+ assertNull(out, "Expected null value.");
+
+ parcLogReporter_Release(&reporter);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogReporter_Create)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(out);
+
+ parcOutputStream_Release(&out);
+
+ assertNull(out, "Expected null value.");
+
+ parcLogReporter_Release(&reporter);
+}
+
+void
+testReporter(PARCLogReporter *reporter, const PARCLogEntry *entry)
+{
+}
+
+LONGBOW_TEST_CASE(Global, parcLogReporter_Create_NULLObject)
+{
+ PARCLogReporter *reporter = parcLogReporter_Create(NULL, NULL, testReporter, NULL);
+
+ parcLogReporter_Release(&reporter);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogReporter_GetPrivateObject)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(out);
+ parcOutputStream_Release(&out);
+
+ void *instance = parcLogReporter_GetPrivateObject(reporter);
+ assertNotNull(instance, "Expected the instance pointer to be non-NULL");
+
+ parcLogReporter_Release(&reporter);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogReporter_Report)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(out);
+ parcOutputStream_Release(&out);
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+
+ parcLogReporter_Report(reporter, entry);
+ parcLogEntry_Release(&entry);
+ parcBuffer_Release(&payload);
+
+ assertNull(out, "Expected null value.");
+
+ parcLogReporter_Release(&reporter);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_LogReporter);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/logging/test/test_parc_LogReporterFile.c b/libparc/parc/logging/test/test_parc_LogReporterFile.c
new file mode 100755
index 00000000..9739c715
--- /dev/null
+++ b/libparc/parc/logging/test/test_parc_LogReporterFile.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 Runner.
+#include "../parc_LogReporterFile.c"
+
+#include <parc/algol/parc_OutputStream.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_LogReporterFile)
+{
+ // 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(parc_LogReporterFile)
+{
+ 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_LogReporterFile)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLogReporterFile_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogReporterFile_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogReporterFile_Report);
+}
+
+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 %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcLogReporterFile_Create)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(out);
+ parcOutputStream_Release(&out);
+
+ assertNull(out, "Expected null value.");
+
+ parcLogReporter_Release(&reporter);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogReporterFile_AcquireRelease)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(out);
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcLogReporterFile_Acquire, reporter);
+
+ parcOutputStream_Release(&out);
+
+ assertNull(out, "Expected null value.");
+
+ parcLogReporterFile_Release(&reporter);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogReporterFile_Report)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(out);
+ parcOutputStream_Release(&out);
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+
+ parcLogReporter_Report(reporter, entry);
+ parcLogEntry_Release(&entry);
+ parcBuffer_Release(&payload);
+
+ assertNull(out, "Expected null value.");
+
+ parcLogReporter_Release(&reporter);
+}
+
+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(parc_LogReporterFile);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/logging/test/test_parc_LogReporterTextStdout.c b/libparc/parc/logging/test/test_parc_LogReporterTextStdout.c
new file mode 100755
index 00000000..004fbd58
--- /dev/null
+++ b/libparc/parc/logging/test/test_parc_LogReporterTextStdout.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_LogReporterTextStdout.c"
+
+#include <stdio.h>
+
+#include <parc/algol/parc_OutputStream.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_LogReporterTextStdout)
+{
+ // 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(parc_LogReporterTextStdout)
+{
+ 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_LogReporterTextStdout)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_LogReporterTextStdout_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parc_LogReporterTextStdout_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parc_LogReporterTextStdout_Report);
+}
+
+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 %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parc_LogReporterTextStdout_Create)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+
+ parcLogReporter_Release(&reporter);
+}
+
+LONGBOW_TEST_CASE(Global, parc_LogReporterTextStdout_AcquireRelease)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcLogReporterTextStdout_Acquire, reporter);
+ parcLogReporterTextStdout_Release(&reporter);
+}
+
+LONGBOW_TEST_CASE(Global, parc_LogReporterTextStdout_Report)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+
+ parcLogReporter_Report(reporter, entry);
+ parcLogEntry_Release(&entry);
+ parcBuffer_Release(&payload);
+
+ parcLogReporter_Release(&reporter);
+}
+
+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[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_LogReporterTextStdout);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/memory/parc_BufferPool.c b/libparc/parc/memory/parc_BufferPool.c
new file mode 100644
index 00000000..d6695fdf
--- /dev/null
+++ b/libparc/parc/memory/parc_BufferPool.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 <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_LinkedList.h>
+
+#include "parc_BufferPool.h"
+
+struct PARCBufferPool {
+ size_t bufferSize;
+ size_t limit;
+ size_t largestPoolSize;
+ size_t totalInstances;
+ size_t cacheHits;
+ PARCLinkedList *freeList;
+ PARCObjectDescriptor *descriptor;
+ const PARCObjectDescriptor *originalDescriptor;
+};
+
+static bool
+_parcBufferPool_Destructor(PARCBufferPool **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCBufferPool pointer.");
+
+ PARCBufferPool *pool = *instancePtr;
+
+ parcLinkedList_Apply(pool->freeList, (void (*))parcObject_SetDescriptor, (const void *) &PARCBuffer_Descriptor);
+
+ parcLinkedList_Release(&pool->freeList);
+ parcObjectDescriptor_Destroy(&pool->descriptor);
+
+ return true;
+}
+
+static bool
+_parcBufferPool_ObjectDestructor(PARCBuffer **bufferPtr)
+{
+ PARCBuffer *buffer = *bufferPtr;
+
+ PARCBufferPool *bufferPool = parcObjectDescriptor_GetTypeState(parcObject_GetDescriptor(buffer));
+
+ parcObject_Synchronize(bufferPool->freeList)
+ {
+ size_t freeListSize = parcLinkedList_Size(bufferPool->freeList);
+
+ if (bufferPool->limit > freeListSize) {
+ parcLinkedList_Append(bufferPool->freeList, buffer);
+ freeListSize++;
+ if (bufferPool->largestPoolSize < freeListSize) {
+ bufferPool->largestPoolSize = freeListSize;
+ }
+ } else {
+ parcBuffer_Acquire(buffer);
+ parcObject_SetDescriptor(buffer, &PARCBuffer_Descriptor);
+ parcBuffer_Release(&buffer);
+ }
+ }
+
+ *bufferPtr = 0;
+ return false;
+}
+
+parcObject_ImplementAcquire(parcBufferPool, PARCBufferPool);
+
+parcObject_ImplementRelease(parcBufferPool, PARCBufferPool);
+
+parcObject_Override(PARCBufferPool, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcBufferPool_Destructor,
+ .isLockable = true);
+
+
+void
+parcBufferPool_AssertValid(const PARCBufferPool *instance)
+{
+ assertTrue(parcBufferPool_IsValid(instance),
+ "PARCBufferPool is not valid.");
+}
+
+PARCBufferPool *
+parcBufferPool_CreateExtending(const PARCObjectDescriptor *originalDescriptor, size_t limit, size_t bufferSize)
+{
+ PARCBufferPool *result = parcObject_CreateInstance(PARCBufferPool);
+
+ if (result != NULL) {
+ result->limit = limit;
+ result->totalInstances = 0;
+ result->cacheHits = 0;
+ result->largestPoolSize = 0;
+ result->bufferSize = bufferSize;
+ result->freeList = parcLinkedList_Create();
+
+ result->originalDescriptor = originalDescriptor;
+
+ char *string = parcMemory_Format("PARCBufferPool=%zu", bufferSize);
+ result->descriptor = parcObjectDescriptor_CreateExtension(result->originalDescriptor, string);
+ result->descriptor->destructor = (PARCObjectDestructor *) _parcBufferPool_ObjectDestructor;
+ result->descriptor->typeState = (PARCObjectTypeState *) result;
+ parcMemory_Deallocate(&string);
+ }
+
+ return result;
+}
+
+PARCBufferPool *
+parcBufferPool_Create(size_t limit, size_t bufferSize)
+{
+ PARCBufferPool *result = parcBufferPool_CreateExtending(&parcObject_DescriptorName(PARCBuffer), limit, bufferSize);
+
+ return result;
+}
+
+void
+parcBufferPool_Display(const PARCBufferPool *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCBufferPool@%p {", instance);
+ /* Call Display() functions for the fields here. */
+ parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool
+parcBufferPool_IsValid(const PARCBufferPool *bufferPool)
+{
+ bool result = false;
+
+ if (bufferPool != NULL) {
+ result = parcLinkedList_IsValid(bufferPool->freeList);
+ }
+
+ return result;
+}
+
+PARCBuffer *
+parcBufferPool_GetInstance(PARCBufferPool *bufferPool)
+{
+ PARCBuffer *result = NULL;
+
+ parcObject_Synchronize(bufferPool->freeList)
+ {
+ if (parcLinkedList_Size(bufferPool->freeList) > 0) {
+ result = parcLinkedList_RemoveFirst(bufferPool->freeList);
+ bufferPool->cacheHits++;
+ } else {
+ result = parcBuffer_Allocate(bufferPool->bufferSize);
+ parcObject_SetDescriptor(result, bufferPool->descriptor);
+ }
+ bufferPool->totalInstances++;
+ }
+
+ return result;
+}
+
+size_t
+parcBufferPool_Drain(PARCBufferPool *bufferPool)
+{
+ size_t result = 0;
+
+ parcObject_Synchronize(bufferPool->freeList)
+ {
+ size_t freeListSize = parcLinkedList_Size(bufferPool->freeList);
+ if (freeListSize > bufferPool->limit) {
+ result = freeListSize - bufferPool->limit;
+ for (size_t i = bufferPool->limit; i < freeListSize; i++) {
+ PARCObject *object = parcLinkedList_RemoveLast(bufferPool->freeList);
+ parcObject_SetDescriptor(object, &PARCBuffer_Descriptor);
+ parcObject_Release(&object);
+ }
+ }
+ }
+
+ return result;
+}
+
+size_t
+parcBufferPool_SetLimit(PARCBufferPool *bufferPool, size_t limit)
+{
+ size_t oldLimit = bufferPool->limit;
+
+ if (limit < bufferPool->limit) {
+ bufferPool->largestPoolSize = bufferPool->limit;
+ }
+
+ bufferPool->limit = limit;
+
+ return oldLimit;
+}
+
+size_t
+parcBufferPool_GetLimit(const PARCBufferPool *bufferPool)
+{
+ return bufferPool->limit;
+}
+
+size_t
+parcBufferPool_GetCurrentPoolSize(const PARCBufferPool *bufferPool)
+{
+ size_t result = parcLinkedList_Size(bufferPool->freeList);
+
+ return result;
+}
+
+size_t
+parcBufferPool_GetLargestPoolSize(const PARCBufferPool *bufferPool)
+{
+ return bufferPool->largestPoolSize;
+}
+
+size_t
+parcBufferPool_GetTotalInstances(const PARCBufferPool *bufferPool)
+{
+ return bufferPool->totalInstances;
+}
+
+size_t
+parcBufferPool_GetCacheHits(const PARCBufferPool *bufferPool)
+{
+ return bufferPool->cacheHits;
+}
diff --git a/libparc/parc/memory/parc_BufferPool.h b/libparc/parc/memory/parc_BufferPool.h
new file mode 100644
index 00000000..33028920
--- /dev/null
+++ b/libparc/parc/memory/parc_BufferPool.h
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_BufferPool.h
+ * @ingroup memory
+ * @brief A simple pool of uniformly sized PARCBuffer instances.
+ *
+ * The client uses `parcBufferPool_GetInstance` to obtain instances which are placed attempted to be placed
+ * into the pool when the `PARCBuffer_Release` function is called.
+ * The pool has a maxmimum number of instances that it will cache.
+ *
+ */
+#ifndef PARCLibrary_parc_BufferPool
+#define PARCLibrary_parc_BufferPool
+#include <stdbool.h>
+
+#include <parc/algol/parc_Object.h>
+
+parcObject_Declare(PARCBufferPool);
+
+/**
+ * Increase the number of references to a `PARCBufferPool` instance.
+ *
+ * Note that new `PARCBufferPool` is not created,
+ * only that the given `PARCBufferPool` reference count is incremented.
+ * Discard the reference by invoking `parcBufferPool_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCBufferPool instance.
+ *
+ * @return The same value as the parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferPool *a = parcBufferPool_Create(5, 10);
+ *
+ * PARCBufferPool *b = parcBufferPool_Acquire(a);
+ *
+ * parcBufferPool_Release(&a);
+ * parcBufferPool_Release(&b);
+ * }
+ * @endcode
+ */
+PARCBufferPool *parcBufferPool_Acquire(const PARCBufferPool *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcBufferPool_OptionalAssertValid(_instance_)
+#else
+# define parcBufferPool_OptionalAssertValid(_instance_) parcBufferPool_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCBufferPool` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCBufferPool instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferPool *a = parcBufferPool_Create(5, 10);
+ *
+ * parcBufferPool_AssertValid(a);
+ *
+ * parcBufferPool_Release(&a);
+ * }
+ * @endcode
+ */
+void parcBufferPool_AssertValid(const PARCBufferPool *instance);
+
+/**
+ * Create an instance of PARCBufferPool containing instances of `PARCBuffer`.
+ *
+ * This function is equivalent to invoking
+ * @code
+ * PARCBufferPool *a = parcBufferPool_CreateExtending(&parcObject_DescriptorName(PARCBuffer), 5, 10);
+ * @endcode
+ *
+ * The value of @p limit is the maximum number of instances that the pool will cache,
+ * and @p bufferSize is the size of the `PARCBuffer` instances cached.
+ *
+ * @return non-NULL A pointer to a valid PARCBufferPool instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferPool *a = parcBufferPool_Create(5, 10);
+ *
+ * parcBufferPool_Release(&a);
+ * }
+ * @endcode
+ */
+PARCBufferPool *parcBufferPool_Create(size_t limit, size_t bufferSize);
+
+/**
+ * Create an instance of PARCBufferPool containing instances of object specified by the given `PARCObjectDescriptor`.
+ *
+ * The value of @p limit is the maximum number of instances that the pool will cache,
+ * and @p bufferSize is the size of the `PARCBuffer` instances cached.
+ *
+ * This function creates a PARCBufferPool that creates and manages instances of PARCBuffer which may have been extended.
+ *
+ * @return non-NULL A pointer to a valid PARCBufferPool instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferPool *a = parcBufferPool_CreateExtending(&parcObject_DescriptorName(MyPARCBuffer), 5, 10);
+ *
+ * parcBufferPool_Release(&a);
+ * }
+ * @endcode
+ */
+PARCBufferPool *parcBufferPool_CreateExtending(const PARCObjectDescriptor *originalDescriptor, size_t limit, size_t bufferSize);
+
+/**
+ * Print a human readable representation of the given `PARCBufferPool`.
+ *
+ * @param [in] instance A pointer to a valid PARCBufferPool instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferPool *a = parcBufferPool_Create(5, 10);
+ *
+ * parcBufferPool_Display(a, 0);
+ *
+ * parcBufferPool_Release(&a);
+ * }
+ * @endcode
+ */
+void parcBufferPool_Display(const PARCBufferPool *instance, int indentation);
+
+/**
+ * Determine if an instance of `PARCBufferPool` 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 PARCBufferPool instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferPool *a = parcBufferPool_Create(5, 10);
+ *
+ * if (parcBufferPool_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcBufferPool_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcBufferPool_IsValid(const PARCBufferPool *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCBufferPool` 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
+ * {
+ * PARCBufferPool *a = parcBufferPool_Create(5, 10);
+ *
+ * parcBufferPool_Release(&a);
+ * }
+ * @endcode
+ */
+void parcBufferPool_Release(PARCBufferPool **instancePtr);
+
+/**
+ * Get an instance of a `PARCBuffer`.
+ *
+ * If the PARCBufferPool contains a cached instance, it will be returned.
+ * Otherwise a new instance will be created.
+ *
+ * Any `PARCBuffer` instance which is later released, will be a candidate for caching by the given `PARCBufferPool`.
+ *
+ * @param [in] bufferPool A pointer to a valid PARCBufferPool instance.
+ *
+ * @return non-NULL A pointer to a valid `PARCBuffer`.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * PARCBufferPool *pool = parcBufferPool_Create(5, 10);
+ * ...
+ *
+ * parcBufferPool_Release(&pool);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcBufferPool_GetInstance(PARCBufferPool *bufferPool);
+
+/**
+ * Set the largest number of buffers the pool will cache.
+ *
+ * If the new limit is less than the current limit, and the current pool size is greater than the new limit,
+ * the number of buffers the pool will cache will decay as they are obtained and released from the pool during use.
+ *
+ * @param [in] bufferPool A pointer to a valid PARCBufferPool instance.
+ * @param [in] limit the largest number of buffers the pool will cache.
+ *
+ * @return The previous value of the largest number of buffers the pool cached.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * PARCBufferPool *pool = parcBufferPool_Create(5, 10);
+ * ...
+ *
+ * size_t limit = parcBufferPool_SetLimit(pool, 3);
+ *
+ * parcBufferPool_Release(&pool);
+ * }
+ * @endcode
+ */
+size_t parcBufferPool_SetLimit(PARCBufferPool *bufferPool, size_t limit);
+
+/**
+ * Get the largest number of buffers the pool will cache.
+ *
+ * @param [in] bufferPool A pointer to a valid PARCBufferPool instance.
+ *
+ * @return The value of the largest number of buffers the pool will cache.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * PARCBufferPool *pool = parcBufferPool_Create(5, 10);
+ * ...
+ *
+ * size_t limit = parcBufferPool_GetLimit(pool);
+ *
+ * parcBufferPool_Release(&pool);
+ * }
+ * @endcode
+ */
+size_t parcBufferPool_GetLimit(const PARCBufferPool *bufferPool);
+
+/**
+ * Get the current number of buffers the pool has cached.
+ *
+ * The value is always greater than or equal to 0 and less than or equal to the limit.
+ *
+ * @param [in] bufferPool A pointer to a valid PARCBufferPool instance.
+ *
+ * @return the largest number of buffers the pool has ever cached.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferPool *pool = parcBufferPool_Create(5, 10);
+ * ...
+ *
+ * size_t poolSize = parcBufferPool_GetCurrentPoolSize(pool);
+ *
+ * parcBufferPool_Release(&pool);
+ * }
+ * @endcode
+ */
+size_t parcBufferPool_GetCurrentPoolSize(const PARCBufferPool *bufferPool);
+
+/**
+ * Get the largest number of buffers the pool has ever cached.
+ *
+ * The value is always greater than or equal to 0 and less than or equal to the limit.
+ *
+ * @param [in] bufferPool A pointer to a valid PARCBufferPool instance.
+ *
+ * @return the largest number of buffers the pool has ever cached.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferPool *pool = parcBufferPool_Create(5, 10);
+ * ...
+ *
+ * size_t allTimeHigh = parcBufferPool_GetLargestPoolSize(pool);
+ *
+ * parcBufferPool_Release(&pool);
+ * }
+ * @endcode
+ */
+size_t parcBufferPool_GetLargestPoolSize(const PARCBufferPool *bufferPool);
+
+/**
+ * Forcibly drain the PARCBufferPool of an excess (more than the pool's limit) `PARCBuffer` instances.
+ *
+ * The number of PARCBuffer instances can exceed the PARCBufferPool's limit if `parcBufferPool_SetLimit` is used to set the limit
+ * to less than Pool's current pool size.
+ *
+ * @param [in] bufferPool A pointer to a valid PARCBufferPool instance.
+ *
+ * @return the largest number of buffers released from the Pool's cache.
+ *
+ * Example:
+ * @code
+ * {
+ *
+ * PARCBufferPool *pool = parcBufferPool_Create(5, 10);
+ * ...
+ *
+ * size_t limit = parcBufferPool_SetLimit(pool, 3);
+ * size_t drained = parcBufferPool_Drain(pool);
+ *
+ * parcBufferPool_Release(&pool);
+ * }
+ * @endcode
+ */
+size_t parcBufferPool_Drain(PARCBufferPool *bufferPool);
+#endif
diff --git a/libparc/parc/memory/test/CMakeLists.txt b/libparc/parc/memory/test/CMakeLists.txt
new file mode 100644
index 00000000..61a5608b
--- /dev/null
+++ b/libparc/parc/memory/test/CMakeLists.txt
@@ -0,0 +1,13 @@
+set(TestsExpectedToPass
+ test_parc_BufferPool
+ )
+
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
+
diff --git a/libparc/parc/memory/test/test_parc_BufferPool.c b/libparc/parc/memory/test/test_parc_BufferPool.c
new file mode 100644
index 00000000..b7c18d08
--- /dev/null
+++ b/libparc/parc/memory/test/test_parc_BufferPool.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_BufferPool.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(parc_BufferPool)
+{
+ // 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(parc_BufferPool)
+{
+ 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_BufferPool)
+{
+ 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))) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCBufferPool *instance = parcBufferPool_Create(3, 10);
+ assertNotNull(instance, "Expected non-null result from parcBufferPool_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcBufferPool_Acquire, instance);
+
+ parcBufferPool_Release(&instance);
+ assertNull(instance, "Expected null result from parcBufferPool_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcBufferPool_Display);
+ LONGBOW_RUN_TEST_CASE(Object, parcBufferPool_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcBufferPool_AssertValid);
+}
+
+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, parcBufferPool_Display)
+{
+ PARCBufferPool *instance = parcBufferPool_Create(3, 10);
+ parcBufferPool_Display(instance, 0);
+ parcBufferPool_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcBufferPool_IsValid)
+{
+ PARCBufferPool *instance = parcBufferPool_Create(3, 10);
+ assertTrue(parcBufferPool_IsValid(instance), "Expected parcBufferPool_Create to result in a valid instance.");
+
+ parcBufferPool_Release(&instance);
+ assertFalse(parcBufferPool_IsValid(instance), "Expected parcBufferPool_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcBufferPool_AssertValid)
+{
+ PARCBufferPool *instance = parcBufferPool_Create(3, 10);
+ parcBufferPool_AssertValid(instance);
+
+ parcBufferPool_Release(&instance);
+ assertFalse(parcBufferPool_IsValid(instance), "Expected parcBufferPool_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_GetInstance);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_GetLargestPoolSize);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_GetCurrentPoolSize);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_GetTotalInstances);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_GetCacheHits);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_GetLimit);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_SetLimit_Increasing);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_SetLimit_Decreasing);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcBufferPool_Drain);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ longBowTestCase_SetInt(testCase, "initialAllocations", parcMemory_Outstanding());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ int initialAllocations = longBowTestCase_GetInt(testCase, "initialAllocations");
+
+ if (parcMemory_Outstanding() > initialAllocations) {
+ parcSafeMemory_ReportAllocation(1);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Specialization, parcBufferPool_GetInstance)
+{
+ PARCBufferPool *pool = parcBufferPool_Create(3, 10);
+
+ PARCBuffer *buffer = parcBufferPool_GetInstance(pool);
+
+ parcBuffer_AssertValid(buffer);
+ parcBuffer_Release(&buffer);
+
+ size_t largestPoolSize = parcBufferPool_GetLargestPoolSize(pool);
+
+ assertTrue(largestPoolSize == 1, "Expected the largestPoolSize to be 1, actual %zu", largestPoolSize);
+
+ parcBufferPool_Release(&pool);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcBufferPool_GetLargestPoolSize)
+{
+ PARCBufferPool *pool = parcBufferPool_Create(3, 10);
+ size_t largestPoolSize = parcBufferPool_GetLargestPoolSize(pool);
+
+ assertTrue(largestPoolSize == 0, "Expected the largestPoolSize to be 0, actual %zu", largestPoolSize);
+
+ PARCBuffer *buffer = parcBufferPool_GetInstance(pool);
+
+ parcBuffer_AssertValid(buffer);
+ parcBuffer_Release(&buffer);
+
+ largestPoolSize = parcBufferPool_GetLargestPoolSize(pool);
+
+ assertTrue(largestPoolSize == 1, "Expected the largestPoolSize to be 1, actual %zu", largestPoolSize);
+
+ parcBufferPool_Release(&pool);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcBufferPool_GetTotalInstances)
+{
+ PARCBufferPool *pool = parcBufferPool_Create(3, 10);
+ size_t totalInstances = parcBufferPool_GetTotalInstances(pool);
+
+ assertTrue(totalInstances == 0, "Expected the totalInstances to be 0, actual %zu", totalInstances);
+
+ PARCBuffer *buffer = parcBufferPool_GetInstance(pool);
+
+ parcBuffer_AssertValid(buffer);
+ parcBuffer_Release(&buffer);
+
+ totalInstances = parcBufferPool_GetTotalInstances(pool);
+
+ assertTrue(totalInstances == 1, "Expected the totalInstances to be 1, actual %zu", totalInstances);
+
+ parcBufferPool_Release(&pool);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcBufferPool_GetCacheHits)
+{
+ PARCBufferPool *pool = parcBufferPool_Create(3, 10);
+ size_t cacheHits = parcBufferPool_GetCacheHits(pool);
+
+ assertTrue(cacheHits == 0, "Expected the cacheHits to be 0, actual %zu", cacheHits);
+
+ PARCBuffer *buffer = parcBufferPool_GetInstance(pool);
+ parcBuffer_AssertValid(buffer);
+ parcBuffer_Release(&buffer);
+
+ cacheHits = parcBufferPool_GetCacheHits(pool);
+ assertTrue(cacheHits == 0, "Expected the cacheHits to be 0, actual %zu", cacheHits);
+
+ buffer = parcBufferPool_GetInstance(pool);
+ parcBuffer_AssertValid(buffer);
+ parcBuffer_Release(&buffer);
+
+ cacheHits = parcBufferPool_GetCacheHits(pool);
+ assertTrue(cacheHits == 1, "Expected the cacheHits to be 1, actual %zu", cacheHits);
+
+ parcBufferPool_Release(&pool);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcBufferPool_GetLimit)
+{
+ size_t expected = 20;
+
+ PARCBufferPool *pool = parcBufferPool_Create(expected, 10);
+ size_t limit = parcBufferPool_GetLimit(pool);
+
+ assertTrue(limit == expected, "Expected the limit to be %zu, actual %zu", expected, limit);
+ parcBufferPool_Release(&pool);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcBufferPool_GetCurrentPoolSize)
+{
+ size_t expectedLimit = 3;
+
+ PARCBufferPool *pool = parcBufferPool_Create(expectedLimit, 10);
+ size_t poolSize = parcBufferPool_GetCurrentPoolSize(pool);
+
+ assertTrue(poolSize == 0, "Expected the poolSize to be 0, actual %zu", poolSize);
+
+ PARCBuffer *buffer1 = parcBufferPool_GetInstance(pool);
+ PARCBuffer *buffer2 = parcBufferPool_GetInstance(pool);
+ PARCBuffer *buffer3 = parcBufferPool_GetInstance(pool);
+ PARCBuffer *buffer4 = parcBufferPool_GetInstance(pool);
+ PARCBuffer *buffer5 = parcBufferPool_GetInstance(pool);
+
+ parcBuffer_Release(&buffer1);
+ parcBuffer_Release(&buffer2);
+ parcBuffer_Release(&buffer3);
+ parcBuffer_Release(&buffer4);
+ parcBuffer_Release(&buffer5);
+
+ poolSize = parcBufferPool_GetCurrentPoolSize(pool);
+
+ assertTrue(poolSize == expectedLimit, "Expected the poolSize to be %zu, actual %zu", expectedLimit, poolSize);
+
+ parcBufferPool_Release(&pool);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcBufferPool_SetLimit_Increasing)
+{
+ size_t oldLimit = 3;
+ size_t newLimit = 5;
+
+ PARCBufferPool *pool = parcBufferPool_Create(oldLimit, 10);
+ size_t limit = parcBufferPool_GetLimit(pool);
+
+ assertTrue(limit == oldLimit, "Expected the limit to be %zu, actual %zu", oldLimit, limit);
+
+ PARCBuffer *buffer1 = parcBufferPool_GetInstance(pool);
+ PARCBuffer *buffer2 = parcBufferPool_GetInstance(pool);
+ PARCBuffer *buffer3 = parcBufferPool_GetInstance(pool);
+ parcBuffer_AssertValid(buffer1);
+ parcBuffer_AssertValid(buffer2);
+ parcBuffer_AssertValid(buffer3);
+ parcBuffer_Release(&buffer1);
+ parcBuffer_Release(&buffer2);
+ parcBuffer_Release(&buffer3);
+
+ limit = parcBufferPool_SetLimit(pool, newLimit);
+ assertTrue(limit == 3, "Expected the old limit to be %zu, actual %zu", oldLimit, limit);
+
+ size_t largestPoolSize = parcBufferPool_GetLargestPoolSize(pool);
+ assertTrue(largestPoolSize == oldLimit, "Expected largest pool size to be %zu, actual %zu", oldLimit, largestPoolSize);
+
+
+ parcBufferPool_Release(&pool);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcBufferPool_SetLimit_Decreasing)
+{
+ size_t oldLimit = 3;
+ size_t newLimit = 2;
+
+ PARCBufferPool *pool = parcBufferPool_Create(oldLimit, 10);
+ size_t limit = parcBufferPool_GetLimit(pool);
+
+ assertTrue(limit == oldLimit, "Expected the limit to be %zu, actual %zu", oldLimit, limit);
+
+ PARCBuffer *buffer1 = parcBufferPool_GetInstance(pool);
+ PARCBuffer *buffer2 = parcBufferPool_GetInstance(pool);
+ PARCBuffer *buffer3 = parcBufferPool_GetInstance(pool);
+ parcBuffer_AssertValid(buffer1);
+ parcBuffer_AssertValid(buffer2);
+ parcBuffer_AssertValid(buffer3);
+ parcBuffer_Release(&buffer1);
+ parcBuffer_Release(&buffer2);
+ parcBuffer_Release(&buffer3);
+
+ limit = parcBufferPool_SetLimit(pool, newLimit);
+ assertTrue(limit == 3, "Expected the old limit to be %zu, actual %zu", oldLimit, limit);
+
+ size_t largestPoolSize = parcBufferPool_GetLargestPoolSize(pool);
+ assertTrue(largestPoolSize == oldLimit, "Expected largest pool size to be %zu, actual %zu", oldLimit, largestPoolSize);
+
+
+ parcBufferPool_Release(&pool);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcBufferPool_Drain)
+{
+ size_t oldLimit = 3;
+ size_t newLimit = 2;
+
+ PARCBufferPool *pool = parcBufferPool_Create(oldLimit, 10);
+
+ PARCBuffer *buffer1 = parcBufferPool_GetInstance(pool);
+ PARCBuffer *buffer2 = parcBufferPool_GetInstance(pool);
+ PARCBuffer *buffer3 = parcBufferPool_GetInstance(pool);
+ parcBuffer_AssertValid(buffer1);
+ parcBuffer_AssertValid(buffer2);
+ parcBuffer_AssertValid(buffer3);
+ parcBuffer_Release(&buffer1);
+ parcBuffer_Release(&buffer2);
+ parcBuffer_Release(&buffer3);
+
+ size_t limit = parcBufferPool_SetLimit(pool, newLimit);
+ assertTrue(limit == oldLimit, "Expected the limit to be %zu, actual %zu", oldLimit, limit);
+
+ size_t drained = parcBufferPool_Drain(pool);
+ assertTrue(drained == 1, "Expected the drained to be 1, actual %zu", drained);
+
+ parcBufferPool_Release(&pool);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_BufferPool);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/object/test/CMakeLists.txt b/libparc/parc/object/test/CMakeLists.txt
new file mode 100644
index 00000000..3be628ab
--- /dev/null
+++ b/libparc/parc/object/test/CMakeLists.txt
@@ -0,0 +1,12 @@
+set(TestsExpectedToPass
+ )
+
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
+
diff --git a/libparc/parc/security/.gitignore b/libparc/parc/security/.gitignore
new file mode 100644
index 00000000..c0f8eeb0
--- /dev/null
+++ b/libparc/parc/security/.gitignore
@@ -0,0 +1,5 @@
+parc_LibraryVersion.c
+test/test_ccnx_FileKeystore
+test/test_ccnx_SelfSignedCertificate
+test/test_ccnx_Signature
+test/test_parc_CryptoHasher
diff --git a/libparc/parc/security/command-line/.gitignore b/libparc/parc/security/command-line/.gitignore
new file mode 100644
index 00000000..988c6e03
--- /dev/null
+++ b/libparc/parc/security/command-line/.gitignore
@@ -0,0 +1 @@
+parc_publickey
diff --git a/libparc/parc/security/command-line/CMakeLists.txt b/libparc/parc/security/command-line/CMakeLists.txt
new file mode 100644
index 00000000..27825978
--- /dev/null
+++ b/libparc/parc/security/command-line/CMakeLists.txt
@@ -0,0 +1,8 @@
+set(PARC_PUBLICKEY_SRC
+ parc-publickey.c
+ parcPublicKey_About.c
+ )
+
+add_executable(parc-publickey ${PARC_PUBLICKEY_SRC})
+target_link_libraries(parc-publickey ${PARC_BIN_LIBRARIES})
+install( TARGETS parc-publickey COMPONENT library RUNTIME DESTINATION bin )
diff --git a/libparc/parc/security/command-line/parc-publickey.c b/libparc/parc/security/command-line/parc-publickey.c
new file mode 100644
index 00000000..56d35935
--- /dev/null
+++ b/libparc/parc/security/command-line/parc-publickey.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <errno.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_PublicKeySigner.h>
+
+void
+parcPublicKey_Create(PARCArrayList *args)
+{
+ unsigned int keyLength = 1024;
+ unsigned int validityDays = 30;
+
+ char *fileName = parcArrayList_Get(args, 2);
+ char *password = parcArrayList_Get(args, 3);
+ char *subjectName = parcArrayList_Get(args, 4);
+ PARCSigningAlgorithm signAlgo = PARCSigningAlgorithm_RSA;
+
+ if (parcArrayList_Size(args) > 5) {
+ keyLength = (unsigned int) strtoul(parcArrayList_Get(args, 5), NULL, 10);
+ }
+
+ if (parcArrayList_Size(args) > 6) {
+ validityDays = (unsigned int) strtoul(parcArrayList_Get(args, 6), NULL, 10);
+ }
+
+ bool result = parcPkcs12KeyStore_CreateFile(fileName, password, subjectName, signAlgo, keyLength, validityDays);
+ if (!result) {
+ printf("Error: %s %s", fileName, strerror(errno));
+ return;
+ }
+ printf("Created %s, key length %d valid for %d days.\n", fileName, keyLength, validityDays);
+}
+
+void
+parcPublicKey_Validate(PARCArrayList *args)
+{
+ char *fileName = parcArrayList_Get(args, 2);
+ char *password = parcArrayList_Get(args, 3);
+
+ PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open(fileName, password, PARCCryptoHashType_SHA256);
+ PARCKeyStore *publicKeyStore = parcKeyStore_Create(keyStore, PARCPkcs12KeyStoreAsKeyStore);
+
+ PARCPublicKeySigner *signer = parcPublicKeySigner_Create(publicKeyStore, PARCCryptoSuite_RSA_SHA256);
+ PARCSigner *pkSigner = parcSigner_Create(signer, PARCPublicKeySignerAsSigner);
+
+ parcKeyStore_Release(&publicKeyStore);
+ parcPkcs12KeyStore_Release(&keyStore);
+
+ if (pkSigner == NULL) {
+ printf("Invalid %s\n", fileName);
+ return;
+ }
+ printf("Valid %s\n", fileName);
+}
+
+void
+printUsage(char *progName)
+{
+ printf("usage: %s [-h | --help] [[-c | --create] fileName password subjectName [keyLength validityDays] | [-v | --validate] fileName password]\n", progName);
+ printf("\n");
+ printf("\n");
+ printf("Create and validate PKCS12 keystores that are used with the CCNx code.\n");
+ printf("\n");
+ printf("optional arguments:\n");
+ printf("\t-h, --help\tShow this help message and exit\n");
+ printf("\t-c, --create\tCreate a PKCS12 keystore with the given filename, password, subject name, and optional key length and validity length (in days)\n");
+ printf("\n");
+ printf("\t\t\texample: ./parc_publickey -c keyfile.pkcs12 <password> <subject name> 1024 365\n");
+ printf("\n");
+ printf("\t-v, --validate\tValidate a PKCS12 file with the given password\n");
+ printf("\n");
+ printf("\t\t\texample: ./parc_publickey -v keyfile.pkcs12 <password>");
+ printf("\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+ char *programName = "parc_publickey";
+ if (argc < 2) {
+ printUsage(programName);
+ exit(1);
+ }
+
+ PARCArrayList *args = parcArrayList_Create(NULL);
+ parcArrayList_AddAll(args, (void **) argv, argc);
+
+ parcSecurity_Init();
+
+ char *arg = parcArrayList_Get(args, 1);
+ if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
+ printUsage(programName);
+ return 0;
+ } else if (strcmp(arg, "-c") == 0 || strcmp(arg, "--create") == 0) {
+ parcPublicKey_Create(args);
+ } else if (strcmp(arg, "-v") == 0 || strcmp(arg, "--validate") == 0) {
+ parcPublicKey_Validate(args);
+ } else {
+ printUsage(programName);
+ exit(1);
+ }
+
+ parcSecurity_Fini();
+ return 0;
+}
diff --git a/libparc/parc/security/command-line/parcPublicKey_About.c b/libparc/parc/security/command-line/parcPublicKey_About.c
new file mode 100644
index 00000000..6a242cf4
--- /dev/null
+++ b/libparc/parc/security/command-line/parcPublicKey_About.c
@@ -0,0 +1,44 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170206.46e2c73a 2017-02-06T08:50:09Z
+
+#include "parcPublicKey_About.h"
+
+const char *parcPublicKey_What = "@(#)" "PARC public key " RELEASE_VERSION " 2017-02-15T13:31:10.603139"
+ "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates.";
+
+const char *
+parcPublicKeyAbout_Name(void)
+{
+ return "PARC public key";
+}
+
+const char *
+parcPublicKeyAbout_Version(void)
+{
+ return RELEASE_VERSION;
+}
+
+const char *
+parcPublicKeyAbout_About(void)
+{
+ return "PARC public key "RELEASE_VERSION " 2017-02-15T13:31:10.603139" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+parcPublicKeyAbout_MiniNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+parcPublicKeyAbout_ShortNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+parcPublicKeyAbout_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/libparc/parc/security/command-line/parcPublicKey_About.h b/libparc/parc/security/command-line/parcPublicKey_About.h
new file mode 100755
index 00000000..64670ad8
--- /dev/null
+++ b/libparc/parc/security/command-line/parcPublicKey_About.h
@@ -0,0 +1,54 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170206.46e2c73a 2017-02-06T08:50:09Z
+
+#ifndef parcPublicKey_About_h
+#define parcPublicKey_About_h
+/**
+ * Embedded string containing information for the what(1) command.
+ *
+ */
+extern const char *parcPublicKey_What;
+
+/**
+ * Return the name as a C string.
+ *
+ * @return The name as a C string.
+ */
+const char *parcPublicKeyAbout_Name(void);
+
+/**
+ * Return the version as a C string.
+ *
+ * @return The version as a C string.
+ */
+const char *parcPublicKeyAbout_Version(void);
+
+/**
+ * Return the About text as a C string.
+ *
+ * @return The About text as a C string.
+ */
+const char *parcPublicKeyAbout_About(void);
+
+/**
+ * Return the minimum copyright notice as a C string.
+ *
+ * @return The minimum copyright notice as a C string.
+ */
+const char *parcPublicKeyAbout_MiniNotice(void);
+
+/**
+ * Return the short copyright notice as a C string.
+ *
+ * @return The short copyright notice as a C string.
+ */
+const char *parcPublicKeyAbout_ShortNotice(void);
+
+/**
+ * Return the long copyright notice as a C string.
+ *
+ * @return The long copyright notice as a C string.
+ */
+const char *parcPublicKeyAbout_LongNotice(void);
+
+#endif // parcPublicKey_About_h
diff --git a/libparc/parc/security/parc_Certificate.c b/libparc/parc/security/parc_Certificate.c
new file mode 100755
index 00000000..aead0fb5
--- /dev/null
+++ b/libparc/parc/security/parc_Certificate.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.
+ */
+
+/*
+ * parc_Certificate.c
+ * PARC Library
+ */
+
+
+#include <config.h>
+#include <stdio.h>
+
+#include <parc/security/parc_Certificate.h>
+#include <parc/security/parc_CertificateType.h>
+#include <parc/security/parc_ContainerEncoding.h>
+
+#include <parc/algol/parc_Object.h>
+
+struct parc_certificate {
+ PARCCertificateInterface *interface;
+ void *instance;
+};
+
+static void
+_parcCertificate_FinalRelease(PARCCertificate **certP)
+{
+ PARCCertificate *certificate = (PARCCertificate *) *certP;
+
+ if (certificate->instance != NULL) {
+ parcObject_Release(&certificate->instance);
+ }
+}
+
+parcObject_ExtendPARCObject(PARCCertificate, _parcCertificate_FinalRelease, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static PARCCertificate *
+_parcCertificate_Create(PARCCertificateInterface *impl, void *instance)
+{
+ PARCCertificate *cert = parcObject_CreateInstance(PARCCertificate);
+ cert->interface = impl;
+ cert->instance = instance;
+ return cert;
+}
+
+parcObject_ImplementAcquire(parcCertificate, PARCCertificate);
+
+parcObject_ImplementRelease(parcCertificate, PARCCertificate);
+
+PARCCertificate *
+parcCertificate_CreateFromInstance(PARCCertificateInterface *impl, void *instance)
+{
+ return _parcCertificate_Create(impl, instance);
+}
+
+PARCCertificateType
+parcCertificate_GetCertificateType(const PARCCertificate *cert)
+{
+ if (cert->interface->GetCertificateType != NULL) {
+ return cert->interface->GetCertificateType(cert->instance);
+ }
+ return PARCCertificateType_Invalid;
+}
+
+PARCContainerEncoding
+parcCertificate_GetContainerEncoding(const PARCCertificate *cert)
+{
+ if (cert->interface->GetContainerEncoding != NULL) {
+ return cert->interface->GetContainerEncoding(cert->instance);
+ }
+ return PARCContainerEncoding_Invalid;
+}
+
+PARCCryptoHash *
+parcCertificate_GetPublicKeyDigest(const PARCCertificate *certificate)
+{
+ if (certificate->interface->GetPublicKeyDigest != NULL) {
+ return certificate->interface->GetPublicKeyDigest(certificate->instance);
+ }
+ return NULL;
+}
+
+PARCCryptoHash *
+parcCertificate_GetCertificateDigest(const PARCCertificate *certificate)
+{
+ if (certificate->interface->GetCertificateDigest != NULL) {
+ return certificate->interface->GetCertificateDigest(certificate->instance);
+ }
+ return NULL;
+}
+
+PARCBuffer *
+parcCertificate_GetDEREncodedCertificate(const PARCCertificate *certificate)
+{
+ if (certificate->interface->GetDEREncodedCertificate != NULL) {
+ return certificate->interface->GetDEREncodedCertificate(certificate->instance);
+ }
+ return NULL;
+}
+
+PARCBuffer *
+parcCertificate_GetDEREncodedPublicKey(const PARCCertificate *certificate)
+{
+ if (certificate->interface->GetDEREncodedPublicKey != NULL) {
+ return certificate->interface->GetDEREncodedPublicKey(certificate->instance);
+ }
+ return NULL;
+}
+
+PARCKey *
+parcCertificate_GetPublicKey(const PARCCertificate *certificate)
+{
+ PARCBuffer *derEncodedVersion = parcCertificate_GetDEREncodedPublicKey(certificate);
+ PARCCryptoHash *keyDigest = parcCertificate_GetPublicKeyDigest(certificate);
+ PARCKeyId *keyId = parcKeyId_Create(parcCryptoHash_GetDigest(keyDigest));
+
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyId, PARCSigningAlgorithm_RSA, derEncodedVersion);
+
+ parcBuffer_Release(&derEncodedVersion);
+ parcCryptoHash_Release(&keyDigest);
+ parcKeyId_Release(&keyId);
+
+ return key;
+}
diff --git a/libparc/parc/security/parc_Certificate.h b/libparc/parc/security/parc_Certificate.h
new file mode 100755
index 00000000..43eb9416
--- /dev/null
+++ b/libparc/parc/security/parc_Certificate.h
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Certificate.h
+ * @ingroup security
+ * @brief The API for a generic certificate.
+ *
+ */
+
+#ifndef libparc_parc_Certificate_h
+#define libparc_parc_Certificate_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/security/parc_CertificateType.h>
+#include <parc/security/parc_ContainerEncoding.h>
+#include <parc/security/parc_CryptoHasher.h>
+#include <parc/security/parc_Signature.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_Key.h>
+
+struct parc_certificate;
+/**
+ * @typedef PARCCertificate
+ * @brief The structure for PARCCertificate
+ */
+typedef struct parc_certificate PARCCertificate;
+
+typedef struct parc_certificate_interface {
+ /**
+ * The hash of the certificate's public key.
+ *
+ * Try using `parcSigner_CreateKeyId` for a sinterfaceer interface.
+ * You must destroy the returned PARCCryptoHash.
+ * For public key, its the SHA256 digest of the public key.
+ * For HMAC, its the SHA256 digest of the secret key.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der
+ * openssl sha256 -out test_rsa_pub_sha256.bin -sha256 -binary < test_rsa_pub.der
+ *
+ * @param [in] certificate A pointer to a concrete `PARCCertificate` instance.
+ *
+ * @return A `PARCCryptoHash` instance.
+ */
+ PARCCryptoHash *(*GetPublicKeyDigest)(void *certificate);
+
+ /**
+ * Returns a copy of the the certificate digest.
+ *
+ * Returns NULL for symmetric keystores.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ * openssl sha256 -out test_rsa_crt_sha256.bin -sha256 -binary < test_rsa_crt.der
+ * Which is also the same as (but not in der format)
+ * openssl x509 -in test_rsa.crt -fingerprint -sha256
+ *
+ * @param [in] certificate A pointer to a concrete `PARCCertificate` instance.
+ *
+ * @return A `PARCCryptoHash` instance which internally contains a hash digest of the certificate.
+ */
+ PARCCryptoHash *(*GetCertificateDigest)(void *certificate);
+
+ /**
+ * Returns a copy of the DER encoded certificate.
+ *
+ * Returns NULL for symmetric keystores.
+ *
+ * Equivalent of:
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ *
+ * @param [in] certificate A pointer to a concrete `PARCCertificate` instance.
+ *
+ * @return A pointer to a `PARCBuffer` containing the encoded certificate.
+ */
+ PARCBuffer *(*GetDEREncodedCertificate)(void *certificate);
+
+ /**
+ * Returns a copy of the encoded public key in DER form.
+ *
+ * Equivalent of (for rsa/sha256):
+ * `openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der`
+ *
+ * @param [in] certificate A pointer to a concrete `PARCCertificate` instance.
+ *
+ * @return A pointer to a `PARCBuffer` containing the encoded public key.
+ */
+ PARCBuffer *(*GetDEREncodedPublicKey)(void *certificate);
+
+ /**
+ * Returns the `PARCCertificateType` of this certificate, i.e., PEM, DER, PKCS12.
+ *
+ * @param [in] certificate A pointer to a concrete `PARCCertificate` instance.
+ *
+ * @return The `PARCCertificateType` associated with this certificate.
+ */
+ PARCCertificateType (*GetCertificateType)(const void *certificate);
+
+ /**
+ * Returns the `PARCContainerEncoding` of this certificate, e.g., X509.
+ *
+ * @param [in] certificate A pointer to a concrete `PARCCertificate` instance.
+ *
+ * @return The `PARCContainerEncoding` associated with this certificate.
+ */
+ PARCContainerEncoding (*GetContainerEncoding)(const void *certificate);
+} PARCCertificateInterface;
+
+/**
+ * Create a generic `PARCCertificate` instance from a concrete `PARCCertificate` instance.
+ *
+ * NOTE: This function should not be used directly. Construct certificates using the
+ * `PARCCertificateFactory` instead.
+ *
+ * @param [in] impl A pointer to a concrete `PARCCertificate` interface implementation.
+ * @param [in] instance A pointer to the instance that implements this interface.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A newly allocated `PARCCertificate` instance containing the concrete
+ * `PARCCertificate` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *certificate = ...;
+ * PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ * }
+ * @endcode
+ */
+PARCCertificate *parcCertificate_CreateFromInstance(PARCCertificateInterface *impl, void *instance);
+
+/**
+ * Increase the number of references to a `PARCCertificate` instance.
+ *
+ * Note that a new `PARCCertificate` is not created,
+ * only that the given `PARCCertificate` reference count is incremented.
+ * Discard the reference by invoking {@link parcCertificate_Release}.
+ *
+ * @param [in] certificate A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCertificate *x = parcCertificate_CreateFromInstance(...);
+ * PARCCertificate *x2 = parcCertificate_Acquire(x);
+ *
+ * parcCertificate_Release(&x);
+ * parcCertificate_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see {@link parcCertificate_Release}
+ */
+PARCCertificate *parcCertificate_Acquire(const PARCCertificate *certificate);
+
+/**
+ * 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] certificateP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCertificate *x = parcCertificate_Acquire(...);
+ *
+ * parcCertificate_Release(&x);
+ * }
+ * @endcode
+ *
+ * @see {@link parcCertificate_Acquire}
+ */
+void parcCertificate_Release(PARCCertificate **certificateP);
+
+/**
+ * Returns the `PARCCertificateType` of this certificate, i.e., X509.
+ *
+ * @param [in] certificate A pointer to a concrete `PARCCertificate` instance.
+ *
+ * @return The `PARCCertificateType` associated with this certificate.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(filename);
+ * PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ *
+ * PARCCertificateType type = parcCertificate_GetCertificateType(wrapper);
+ * // type == PARCCertificateType_X509
+ * }
+ * @endcode
+ */
+PARCCertificateType parcCertificate_GetCertificateType(const PARCCertificate *certificate);
+
+/**
+ * Returns the `PARCContainerEncoding` of this certificate, e.g., PEM, DER.
+ *
+ * @param [in] certificate A pointer to a concrete `PARCCertificate` instance.
+ *
+ * @return The `PARCContainerEncoding` associated with this certificate.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(filename);
+ * PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ *
+ * PARCContainerEncoding encoding = parcCertificate_GetCertificateType(wrapper);
+ * // encoding == PARCCertificateType_PEM
+ * }
+ * @endcode
+ */
+PARCContainerEncoding parcCertificate_GetContainerEncoding(const PARCCertificate *certificate);
+
+/**
+ * Retrieve the SHA-256 hash digest of the certificate's public key.
+ *
+ * You must release the returned `PARCCryptoHash` via {@link parcCryptoHash_Release}.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der
+ * openssl sha256 -out test_rsa_pub_sha256.bin -sha256 -binary < test_rsa_pub.der
+ *
+ * @param [in] certificate A pointer to a `PARCCertificate` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A `PARCCryptoHash` value which internally contains a hash digest of the certificate key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(filename);
+ * PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ *
+ * PARCCryptoHash *certificateKeyDigest = parcCertificate_GetPublicKeyDigest(wrapper);
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcCertificate_GetPublicKeyDigest(const PARCCertificate *certificate);
+
+/**
+ * Get the SHA-256 digest of the certificate.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ * openssl sha256 -out test_rsa_crt_sha256.bin -sha256 -binary < test_rsa_crt.der
+ * Which is also the same as (but not in der format)
+ * openssl x509 -in test_rsa.crt -fingerprint -sha256
+ *
+ * @param [in] certificate A pointer to a `PARCCertificate` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return A `PARCCryptoHash` instance which internally contains a hash digest of the certificate.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(filename);
+ * PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ *
+ * PARCCryptoHash *certificateKeyDigest = parcCertificate_GetPublicKeyDigest(wrapper);
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcCertificate_GetCertificateDigest(const PARCCertificate *certificate);
+
+/**
+ * Get a `PARCBuffer` containing the DER encoded representation of the certificate.
+ *
+ * Equivalent of:
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ *
+ * @param [in] certificate A pointer to a `PARCCertificate` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a `PARCBuffer` containing the encoded certificate.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(filename);
+ * PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ *
+ * PARCBuffer *certificateDER = parcCertificate_GetDEREncodedCertificate(wrapper);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcCertificate_GetDEREncodedCertificate(const PARCCertificate *certificate);
+
+/**
+ * Get the certificate's public key in DER encoding in a `PARCBuffer`.
+ *
+ * Equivalent of (for rsa/sha256):
+ * `openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der`
+ *
+ * @param [in] certificate A pointer to a `PARCCertificate` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a `PARCBuffer` containing the encoded certificate's public key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(filename);
+ * PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ *
+ * PARCBuffer *certificateDER = parcCertificate_GetDEREncodedPublicKey(wrapper);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcCertificate_GetDEREncodedPublicKey(const PARCCertificate *certificate);
+
+/**
+ * Get the `PARCKey` public key associated with this certificate.
+ *
+ * @param [in] certificate A pointer to a `PARCCertificate` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a `PARCKey` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(filename);
+ * PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ *
+ * PARCKey *publicKey = parcCertificate_GetPublicKey(wrapper);
+ * }
+ * @endcode
+ */
+PARCKey *parcCertificate_GetPublicKey(const PARCCertificate *certificate);
+#endif // libparc_parc_Certificate_h
diff --git a/libparc/parc/security/parc_CertificateFactory.c b/libparc/parc/security/parc_CertificateFactory.c
new file mode 100644
index 00000000..52cef4af
--- /dev/null
+++ b/libparc/parc/security/parc_CertificateFactory.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.
+ */
+
+/*
+ * parc_CertificateFactory.c
+ * PARC Library
+ */
+
+#include <config.h>
+
+#include <parc/security/parc_CertificateFactory.h>
+#include <parc/security/parc_X509Certificate.h>
+
+#include <parc/algol/parc_Object.h>
+
+struct parc_certificate_factory {
+ PARCCertificateType type;
+ PARCContainerEncoding encoding;
+};
+
+parcObject_ExtendPARCObject(PARCCertificateFactory, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(parcCertificateFactory, PARCCertificateFactory);
+parcObject_ImplementRelease(parcCertificateFactory, PARCCertificateFactory);
+
+PARCCertificateFactory *
+parcCertificateFactory_Create(PARCCertificateType type, PARCContainerEncoding encoding)
+{
+ PARCCertificateFactory *factory = parcObject_CreateInstance(PARCCertificateFactory);
+ factory->type = type;
+ factory->encoding = encoding;
+ return factory;
+}
+
+PARCCertificate *
+parcCertificateFactory_CreateCertificateFromFile(PARCCertificateFactory *factory, const char *filename, const char *password __attribute__((unused)))
+{
+ if (factory->type == PARCCertificateType_X509 && factory->encoding == PARCContainerEncoding_PEM) {
+ PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(filename);
+ PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ return wrapper;
+ }
+
+ // Unsupported configuration
+ return NULL;
+}
+
+PARCCertificate *
+parcCertificateFactory_CreateCertificateFromBuffer(PARCCertificateFactory *factory, PARCBuffer *buffer)
+{
+ if (factory->type == PARCCertificateType_X509 && factory->encoding == PARCContainerEncoding_DER) {
+ PARCX509Certificate *certificate = parcX509Certificate_CreateFromDERBuffer(buffer);
+
+ // This may fail.
+ if (certificate == NULL) {
+ return NULL;
+ }
+
+ PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ return wrapper;
+ }
+
+ // Unsupported configuration
+ return NULL;
+}
+
+PARCCertificate *
+parcCertificateFactory_CreateSelfSignedCertificate(PARCCertificateFactory *factory, PARCBuffer **privateKey,
+ char *subjectName, PARCSigningAlgorithm signAlgo,
+ size_t keyLength, size_t valdityDays)
+{
+ if (factory->type == PARCCertificateType_X509 && factory->encoding == PARCContainerEncoding_DER) {
+ PARCX509Certificate *certificate = NULL;
+ switch (signAlgo)
+ {
+ case PARCSigningAlgorithm_RSA:
+ certificate = parcX509Certificate_CreateSelfSignedCertificate(privateKey, subjectName, (int) keyLength, valdityDays, PARCKeyType_RSA);
+ break;
+ case PARCSigningAlgorithm_ECDSA:
+ certificate = parcX509Certificate_CreateSelfSignedCertificate(privateKey, subjectName, (int) keyLength, valdityDays, PARCKeyType_EC);
+ break;
+ }
+
+ // This may fail.
+ if (certificate == NULL) {
+ return NULL;
+ }
+
+ PARCCertificate *wrapper = parcCertificate_CreateFromInstance(PARCX509CertificateInterface, certificate);
+ return wrapper;
+ }
+
+ // Unsupported configuration
+ return NULL;
+}
diff --git a/libparc/parc/security/parc_CertificateFactory.h b/libparc/parc/security/parc_CertificateFactory.h
new file mode 100755
index 00000000..74035232
--- /dev/null
+++ b/libparc/parc/security/parc_CertificateFactory.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 parc_CertificateFactory.h
+ * @ingroup security
+ * @brief A factory to build certificates.
+ *
+ */
+#ifndef libparc_parc_CertificateFactory_h
+#define libparc_parc_CertificateFactory_h
+
+#include <parc/security/parc_Certificate.h>
+#include <parc/security/parc_CertificateType.h>
+#include <parc/security/parc_ContainerEncoding.h>
+
+struct parc_certificate_factory;
+typedef struct parc_certificate_factory PARCCertificateFactory;
+
+/**
+ * Create a `PARCCertificateFactory` to build certificates with the specified type and encoding.
+ *
+ * @param [in] type The `PARCCertificateType` of certificates to construct.
+ * @param [in] encoding The `PARCContainerEncoding` of certificates to construct.
+ *
+ * @return NULL The memory could not be allocated.
+ * @return non-NULL A newly allocated `PARCCertificateFactory`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_PEM);
+ * }
+ * @endcode
+ */
+PARCCertificateFactory *parcCertificateFactory_Create(PARCCertificateType type, PARCContainerEncoding encoding);
+
+/**
+ * Create a `PARCCertificate` from the specified filename and password.
+ *
+ * @param [in] factory The `PARCCertificateFactory` instance used to build the certificate.
+ * @param [in] filename A nul-terminated path to the certificate file.
+ * @param [in] password A nul-terminated password.
+ *
+ * @return NULL The memory could not be allocated.
+ * @return non-NULL A newly allocated `PARCCertificate`.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pathToCertificate = "file.pem";
+ * PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_PEM);
+ * PARCCertificate *certificate = parcCertificateFactory_CreateCertificateFromFile(factory, pathToCertificate, NULL);
+ * }
+ * @endcode
+ */
+PARCCertificate *parcCertificateFactory_CreateCertificateFromFile(PARCCertificateFactory *factory, const char *filename, const char *password);
+
+/**
+ * Create a `PARCCertificate` from the specified `PARCBuffer`.
+ *
+ * @param [in] factory The `PARCCertificateFactory` instance used to build the certificate.
+ * @param [in] buffer A `PARCBuffer` encoding a `PARCCertificate` instance.
+ *
+ * @return NULL The memory could not be allocated.
+ * @return non-NULL A newly allocated `PARCCertificate`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = ...;
+ * PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_DER);
+ * PARCCertificate *certificate = parcCertificateFactory_CreateCertificateFromBuffer(factory, buffer);
+ * }
+ * @endcode
+ */
+PARCCertificate *parcCertificateFactory_CreateCertificateFromBuffer(PARCCertificateFactory *factory, PARCBuffer *buffer);
+
+/**
+ * Create a self-signed `PARCCertificate` using the specified parameters and return
+ * the corresponding private key.
+ *
+ * Note: this is equivalent to the following OpenSSL command:
+ * XXXXYYYYZZZZ
+ * TODO TODO TODO
+ *
+ * @param [in] factory The `PARCCertificateFactory` instance used to build the certificate.
+ * @param [in, out] privateKey A pointer to a `PARCBuffer` pointer where the new certificate private key will be stored.
+ * @param [in] subjectName The name of the certificate subject.
+ * @param [in] keyLength The length of the public key to be derived.
+ * @param [in] validityDays The validity period.
+ *
+ * @return NULL The memory could not be allocated.
+ * @return non-NULL A newly allocated `PARCCertificate`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = ...;
+ * PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_DER);
+ * PARCCertificate *certificate = parcCertificateFactory_CreateCertificateFromBuffer(factory, buffer);
+ * }
+ * @endcode
+ */
+PARCCertificate *parcCertificateFactory_CreateSelfSignedCertificate(PARCCertificateFactory *factort, PARCBuffer **privateKey, char *subjectName, PARCSigningAlgorithm signAlgo, size_t keyLength, size_t valdityDays);
+
+/**
+ * Increase the number of references to a `PARCCertificateFactory` instance.
+ *
+ * Note that a new `PARCCertificateFactory` is not created,
+ * only that the given `PARCCertificateFactory` reference count is incremented.
+ * Discard the reference by invoking {@link parcCertificateFactory_Release}.
+ *
+ * @param [in] certificate A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCertificateFactory *x = parcCertificateFactory_CreateFromFile(...);
+ * PARCCertificateFactory *x2 = parcCertificateFactory_Acquire(x);
+ *
+ * parcCertificateFactory_Release(&x);
+ * parcCertificateFactory_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see {@link parcCertificateFactory_Release}
+ */
+PARCCertificateFactory *parcCertificateFactory_Acquire(const PARCCertificateFactory *factory);
+
+/**
+ * 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] factoryP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCertificateFactory *x = parcCertificateFactory_CreateFromFile(...);
+ *
+ * parcCertificateFactory_Release(&x);
+ * }
+ * @endcode
+ */
+void parcCertificateFactory_Release(PARCCertificateFactory **factoryP);
+#endif // libparc_parc_CertificateFactory_h
diff --git a/libparc/parc/security/parc_CertificateType.c b/libparc/parc/security/parc_CertificateType.c
new file mode 100755
index 00000000..9da557fd
--- /dev/null
+++ b/libparc/parc/security/parc_CertificateType.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 <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_CertificateType.h>
+
+static struct {
+ PARCCertificateType type;
+ char *name;
+} _certificateType_ToString[] = {
+ { PARCCertificateType_X509, "PARCCertificateType_X509" },
+ { 0, NULL }
+};
+
+const char *
+parcCertificateType_ToString(PARCCertificateType type)
+{
+ for (int i = 0; _certificateType_ToString[i].name != NULL; i++) {
+ if (_certificateType_ToString[i].type == type) {
+ return _certificateType_ToString[i].name;
+ }
+ }
+ return NULL;
+}
+
+PARCCertificateType
+parcCertificateType_FromString(const char *name)
+{
+ for (int i = 0; _certificateType_ToString[i].name != NULL; i++) {
+ if (strcmp(_certificateType_ToString[i].name, name) == 0) {
+ return _certificateType_ToString[i].type;
+ }
+ }
+ return PARCCertificateType_Invalid;
+}
diff --git a/libparc/parc/security/parc_CertificateType.h b/libparc/parc/security/parc_CertificateType.h
new file mode 100755
index 00000000..596cd293
--- /dev/null
+++ b/libparc/parc/security/parc_CertificateType.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 parc_CertificateType.h
+ * @ingroup security
+ * @brief A type specifying a certificate.
+ *
+ */
+#ifndef libparc_parc_CertificateType_h
+#define libparc_parc_CertificateType_h
+
+typedef enum {
+ PARCCertificateType_X509,
+ PARCCertificateType_Invalid
+} PARCCertificateType;
+
+/**
+ * Convert the `PARCCertificateType` value to a human-readable string representation.
+ *
+ * @param [in] type A `PARCCertificateType` value
+ *
+ * @return A static, null-terminated string.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCertificateType type = PARCCertificateType_X509;
+ * const char *stringRep = parcCertificateType_ToString(type);
+ * // use stringRep as necessary, and then free
+ * }
+ * @endcode
+ */
+const char *parcCertificateType_ToString(PARCCertificateType type);
+
+/**
+ * Convert a string representation value of a `PARCCertificateType` to an actual value.
+ *
+ * @param [in] name A string representation of a `PARCCertificateType` value.
+ *
+ * @return A `PARCCertificateType` value.
+ *
+ * Example:
+ * @code
+ * {
+ * const char stringRep[17] = "PARCCertificateType_X509";
+ * PARCCertificateType type = parcCertificateType_FromString(stringRep);
+ * // use stringRep as necessary, and then free
+ * }
+ * @endcode
+ */
+PARCCertificateType parcCertificateType_FromString(const char *name);
+#endif // libparc_parc_CertificateType_h
diff --git a/libparc/parc/security/parc_ContainerEncoding.c b/libparc/parc/security/parc_ContainerEncoding.c
new file mode 100755
index 00000000..8f51031a
--- /dev/null
+++ b/libparc/parc/security/parc_ContainerEncoding.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_ContainerEncoding.h>
+
+static struct {
+ PARCContainerEncoding type;
+ char *name;
+} _certificateType_ToString[] = {
+ { PARCContainerEncoding_PEM, "PARCContainerEncoding_PEM" },
+ { PARCContainerEncoding_DER, "PARCContainerEncoding_DER" },
+ { PARCContainerEncoding_PKCS12, "PARCContainerEncoding_PKCS12" },
+ { 0, NULL }
+};
+
+const char *
+parcContainerEncoding_ToString(PARCContainerEncoding type)
+{
+ for (int i = 0; _certificateType_ToString[i].name != NULL; i++) {
+ if (_certificateType_ToString[i].type == type) {
+ return _certificateType_ToString[i].name;
+ }
+ }
+ return NULL;
+}
+
+PARCContainerEncoding
+parcContainerEncoding_FromString(const char *name)
+{
+ for (int i = 0; _certificateType_ToString[i].name != NULL; i++) {
+ if (strcmp(_certificateType_ToString[i].name, name) == 0) {
+ return _certificateType_ToString[i].type;
+ }
+ }
+ return PARCContainerEncoding_Invalid;
+}
diff --git a/libparc/parc/security/parc_ContainerEncoding.h b/libparc/parc/security/parc_ContainerEncoding.h
new file mode 100755
index 00000000..7cac3fd1
--- /dev/null
+++ b/libparc/parc/security/parc_ContainerEncoding.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_ContainerEncoding.h
+ * @ingroup security
+ * @brief A Encoding specifying a certificate.
+ *
+ */
+#ifndef libparc_parc_Encoding_h
+#define libparc_parc_Encoding_h
+
+typedef enum {
+ PARCContainerEncoding_PEM,
+ PARCContainerEncoding_DER,
+ PARCContainerEncoding_PKCS12,
+ PARCContainerEncoding_Invalid
+} PARCContainerEncoding;
+
+/**
+ * Convert the `PARCContainerEncoding` value to a human-readable string representation.
+ *
+ * @param [in] Encoding A `PARCContainerEncoding` value
+ *
+ * @return A static, null-terminated string.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCContainerEncoding encoding = PARCContainerEncoding_X509;
+ * const char *stringRep = parcContainerEncoding_ToString(encoding);
+ * // use stringRep as necessary, and then free
+ * }
+ * @endcode
+ */
+const char *parcContainerEncoding_ToString(PARCContainerEncoding Encoding);
+
+/**
+ * Convert a string representation value of a `PARCContainerEncoding` to an actual value.
+ *
+ * @param [in] name A string representation of a `PARCContainerEncoding` value.
+ *
+ * @return A `PARCContainerEncoding` value.
+ *
+ * Example:
+ * @code
+ * {
+ * const char stringRep[17] = "PARCContainerEncoding_PEM";
+ * PARCContainerEncoding encoding = parcContainerEncoding_FromString(stringRep);
+ * // use stringRep as necessary, and then free
+ * }
+ * @endcode
+ */
+PARCContainerEncoding parcContainerEncoding_FromString(const char *name);
+#endif // libparc_parc_Encoding_h
diff --git a/libparc/parc/security/parc_CryptoCache.c b/libparc/parc/security/parc_CryptoCache.c
new file mode 100755
index 00000000..a454819b
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoCache.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.
+ */
+
+/**
+ * @header parc_CryptoCache.c
+ * <#Abstract#>
+ *
+ * <#Discussion#>
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+/*
+ * This should be updated to make a reference counted copy of PARCKey and store that (along with its KeyId)
+ * instead of using a direct copy of the user data. That way, there's no issues about destroying the entry
+ * but the user retaining a (now invalid) reference to it.
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/security/parc_CryptoCache.h>
+#include <parc/algol/parc_HashCodeTable.h>
+
+struct parc_crypto_cache {
+ PARCHashCodeTable *keyid_table;
+};
+
+// =====================================================================
+// Translations from void* to typed pointer for use in HashCodeTable
+
+static bool
+_keyidEquals(const void *ptrA, const void *ptrB)
+{
+ return parcKeyId_Equals((const PARCKeyId *) ptrA, (const PARCKeyId *) ptrB);
+}
+
+static void
+_dataDestroy(void **voidPtr)
+{
+ PARCKey **keyPtr = (PARCKey **) voidPtr;
+ parcKey_Release(keyPtr);
+}
+
+// =====================================================================
+
+PARCCryptoCache *
+parcCryptoCache_Create()
+{
+ PARCCryptoCache *cache = parcMemory_AllocateAndClear(sizeof(PARCCryptoCache));
+ assertNotNull(cache, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCCryptoCache));
+
+ // KeyIdDestroyer is NULL because we get the keyid out of the key, and it will be destroyed
+ // when the key is destroyed.
+ cache->keyid_table = parcHashCodeTable_Create(_keyidEquals, parcKeyId_HashCodeFromVoid, NULL, _dataDestroy);
+
+ return cache;
+}
+
+/**
+ * Destroys the cache and all internal buffers.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void
+parcCryptoCache_Destroy(PARCCryptoCache **cryptoCachePtr)
+{
+ assertNotNull(cryptoCachePtr, "Parameter must be non-null double pointer");
+ assertNotNull(*cryptoCachePtr, "Parameter must dereference to non-null pointer");
+
+ PARCCryptoCache *cache = *cryptoCachePtr;
+ parcHashCodeTable_Destroy(&cache->keyid_table);
+ parcMemory_Deallocate((void **) cryptoCachePtr);
+ *cryptoCachePtr = NULL;
+}
+
+/**
+ * Adds the specified key to the keycache.
+ *
+ * Parameters must be non-null
+ * Returns true if added or false if keyid alredy existed and was a different than <code>key</code>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool
+parcCryptoCache_AddKey(PARCCryptoCache *cache, PARCKey *original_key)
+{
+ assertNotNull(cache, "Parameter cache must be non-null");
+ assertNotNull(original_key, "Parameter key must be non-null");
+
+ PARCKey *key = parcKey_Copy(original_key);
+ PARCKeyId *keyid = parcKey_GetKeyId(key);
+
+ return parcHashCodeTable_Add(cache->keyid_table, keyid, key);
+}
+
+/**
+ * Fetches the Key. The user must node modify or destroy the key.
+ *
+ * Returns NULL if the keyid is not found.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const PARCKey *
+parcCryptoCache_GetKey(PARCCryptoCache *cache, const PARCKeyId *keyid)
+{
+ assertNotNull(cache, "Parameter cache must be non-null");
+ assertNotNull(keyid, "Parameter keyid must be non-null");
+
+ return parcHashCodeTable_Get(cache->keyid_table, keyid);
+}
+
+/**
+ * Removes the keyid and key. The internal buffers are destroyed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void
+parcCryptoCache_RemoveKey(PARCCryptoCache *cache, const PARCKeyId *keyid)
+{
+ assertNotNull(cache, "Parameter cache must be non-null");
+ assertNotNull(keyid, "Parameter keyid must be non-null");
+
+ parcHashCodeTable_Del(cache->keyid_table, keyid);
+}
diff --git a/libparc/parc/security/parc_CryptoCache.h b/libparc/parc/security/parc_CryptoCache.h
new file mode 100755
index 00000000..497ee38d
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoCache.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_CryptoCache.h
+ * @ingroup security
+ * @brief In-memory cache of keys or certificates.
+ *
+ * Not sure how to differentiate between keys and certs at the moment. The current API
+ * is thus built around keys.
+ *
+ */
+#include <parc/security/parc_Key.h>
+
+#ifndef libparc_parc_CryptoCache_h
+#define libparc_parc_CryptoCache_h
+
+struct parc_crypto_cache;
+typedef struct parc_crypto_cache PARCCryptoCache;
+
+PARCCryptoCache *parcCryptoCache_Create(void);
+
+/**
+ * Destroys the cache and all internal buffers.
+ *
+ * @param [in,out] cryptoCachePtr A pointer to a pointer to a `PARCCryptoCache` instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcCryptoCache_Destroy(PARCCryptoCache **cryptoCachePtr);
+
+/**
+ * Adds the specified key to the keycache.
+ *
+ * Parameters must be non-null
+ * Returns true if added or false if keyid alredy existed and was a different than <code>key</code>
+ * This will store its own reference to the key, so the caller must free key.
+ *
+ * @param [in] cache A pointer to a PARCCryptoCache instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCKey *key = ....;
+ * PARCCryptoCache *cache = parcCryptoCache_Create();
+ * parcCryptoCache_AddKey(cache, key);
+ * parcKey_release(&key);
+ * // do stuff with the crypto cache
+ * parcCryptoCache_Destroy(&cache);
+ * }
+ * @endcode
+ */
+bool parcCryptoCache_AddKey(PARCCryptoCache *cache, PARCKey *key);
+
+/**
+ * Fetches the Key. The user must not modify or destroy the key.
+ *
+ * Returns NULL if the keyid is not found.
+ *
+ * @param [in] cache A pointer to a PARCCryptoCache instance.
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const PARCKey *parcCryptoCache_GetKey(PARCCryptoCache *cache, const PARCKeyId *keyid);
+
+/**
+ * Removes the keyid and key. The internal buffers are destroyed.
+ *
+ * @param [in] cache A pointer to a PARCCryptoCache instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcCryptoCache_RemoveKey(PARCCryptoCache *cache, const PARCKeyId *keyid);
+#endif // libparc_parc_CryptoCache_h
diff --git a/libparc/parc/security/parc_CryptoHash.c b/libparc/parc/security/parc_CryptoHash.c
new file mode 100755
index 00000000..3fc40b16
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoHash.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parcCryptoHash.c
+ * <#Abstract#>
+ *
+ * <#Discussion#>
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#include <config.h>
+#include <stdio.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_CryptoHash.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/algol/parc_Object.h>
+
+struct parc_crypto_hash {
+ PARCCryptoHashType type;
+ PARCBuffer *digestBuffer;
+};
+
+static bool
+_parcCryptoHash_FinalRelease(PARCCryptoHash **hashP)
+{
+ PARCCryptoHash *hash = (PARCCryptoHash *) *hashP;
+ if (hash->digestBuffer != NULL) {
+ parcBuffer_Release(&hash->digestBuffer);
+ }
+ return true;
+}
+
+parcObject_Override(PARCCryptoHash, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcCryptoHash_FinalRelease,
+ .equals = (PARCObjectEquals *) parcCryptoHash_Equals);
+
+parcObject_ImplementAcquire(parcCryptoHash, PARCCryptoHash);
+
+parcObject_ImplementRelease(parcCryptoHash, PARCCryptoHash);
+
+PARCCryptoHash *
+parcCryptoHash_Create(PARCCryptoHashType digestType, const PARCBuffer *digestBuffer)
+{
+ PARCCryptoHash *parcDigest = parcObject_CreateInstance(PARCCryptoHash);
+ assertNotNull(parcDigest, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCCryptoHash));
+ parcDigest->type = digestType;
+
+ parcDigest->digestBuffer = parcBuffer_Acquire((PARCBuffer *) digestBuffer); // casting to un-const
+
+ return parcDigest;
+}
+
+/**
+ * Create a digest, copying the buffer
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCCryptoHash *
+parcCryptoHash_CreateFromArray(PARCCryptoHashType digestType, const void *buffer, size_t length)
+{
+ PARCCryptoHash *parcDigest = parcObject_CreateInstance(PARCCryptoHash);
+ assertNotNull(parcDigest, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCCryptoHash));
+ parcDigest->type = digestType;
+
+ // create a reference counted copy
+ parcDigest->digestBuffer =
+ parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(length), length, buffer));
+
+ return parcDigest;
+}
+
+/**
+ * Returns the digest algorithm.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCCryptoHashType
+parcCryptoHash_GetDigestType(const PARCCryptoHash *parcDigest)
+{
+ assertNotNull(parcDigest, "Parameter must be non-null");
+ return parcDigest->type;
+}
+
+bool
+parcCryptoHash_Equals(const PARCCryptoHash *a, const PARCCryptoHash *b)
+{
+ if (a == b) {
+ return true;
+ }
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+
+ if (a->type == b->type) {
+ if (parcBuffer_Equals(a->digestBuffer, b->digestBuffer)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+PARCBuffer *
+parcCryptoHash_GetDigest(const PARCCryptoHash *parcDigest)
+{
+ assertNotNull(parcDigest, "Parameter must be non-null");
+ return parcDigest->digestBuffer;
+}
diff --git a/libparc/parc/security/parc_CryptoHash.h b/libparc/parc/security/parc_CryptoHash.h
new file mode 100755
index 00000000..d0312d9e
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoHash.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_CryptoHash.h
+ * @ingroup security
+ *
+ * @brief PARCDigest holds a cryptographic digest, which is comprised
+ * the bytes of the digest and the algorithm used for the digest.
+ *
+ */
+#ifndef libparc_parc_CryptoHash_h
+#define libparc_parc_CryptoHash_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/security/parc_CryptoHashType.h>
+
+struct parc_crypto_hash;
+typedef struct parc_crypto_hash PARCCryptoHash;
+
+/**
+ * Create a Digest holding the type and digest buffer.
+ *
+ * Creates a new reference to the given PARCBuffer `digest`.
+ *
+ * @param [in] digestType The type of hash digest algorithm used to compute this digest.
+ * @param [in] digestBuffer The actual hash digest instance.
+ *
+ * @return A newly allocated `PARCCryptoHash` instance that must be freed via `parcCryptoHash_Release()`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *digestBuffer = ...
+ * PARCCryptoHash *digest = parcCryptoHash_Create(PARCCryptoHashType_SHA256, digestBuffer);
+ * ...
+ * parcCryptoHash_Release(&digest);
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcCryptoHash_Create(PARCCryptoHashType digestType, const PARCBuffer *digestBuffer);
+
+/**
+ * Increase the number of references to a `PARCCryptoHash` instance.
+ *
+ * Note that a new `PARCCryptoHash` is not created,
+ * only that the given `PARCCryptoHash` reference count is incremented.
+ * Discard the reference by invoking {@link parcCryptoHash_Release}.
+ *
+ * @param [in] hash A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHash *x = ...
+ * PARCCryptoHash *x2 = parcCryptoHash_Acquire(x);
+ *
+ * parcCryptoHash_Release(&x);
+ * parcCryptoHash_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see {@link parcCryptoHash_Release}
+ */
+PARCCryptoHash *parcCryptoHash_Acquire(const PARCCryptoHash *hash);
+
+/**
+ * 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] hashP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHash *x = ...
+ *
+ * parcCryptoHash_Release(&x);
+ * }
+ * @endcode
+ *
+ * @see {@link parcCryptoHash_Acquire}
+ */
+void parcCryptoHash_Release(PARCCryptoHash **hashP);
+
+/**
+ * Create a digest, copying the buffer.
+ *
+ * @param [in] digestType The type of hash digest algorithm used to compute this digest.
+ * @param [in] buffer Pointer to array containing the raw digest bytes.
+ * @param [in] length Length of the digest byte array.
+ *
+ * @return A newly allocated `PARCCryptoHash` instance that must be freed via `parcCryptoHash_Release()`
+ *
+ * Example:
+ * @code
+ * {
+ * size_t bufferLen = 32;
+ * uint8_t *buffer = ...
+ * PARCCryptoHash *digest = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer, bufferLen);
+ * ...
+ * parcCryptoHash_Release(&digest);
+ * // free the raw buffer as needed
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcCryptoHash_CreateFromArray(PARCCryptoHashType digestType, const void *buffer, size_t length);
+
+/**
+ * Destroy the specified `PARCCryptoHash` instance.
+ *
+ * @param [in,out] parcDigestPtr Pointer to the instance to be destroyed.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = ...
+ * PARCCryptoHash *digest = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+ * ...
+ * parcCryptoHash_Release(&digest);
+ * }
+ * @endcode
+ */
+void parcCryptoHash_Release(PARCCryptoHash **parcDigestPtr);
+
+/**
+ * Returns the digest algorithm, of type `PARCCryptoHashType`.
+ *
+ * @param [in] parcDigest The `PARCCryptoHash` instance being examined.
+ *
+ * @return A `PARCCryptoHashType` value.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = ...
+ * PARCCryptoHash *digest = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+ * PARCCryptoHashType type = parcCryptoHash_GetDigestType(digest);
+ * // type will be PARCCryptoHashType_SHA256
+ * ...
+ * parcCryptoHash_Release(&digest);
+ * }
+ * @endcode
+ */
+PARCCryptoHashType parcCryptoHash_GetDigestType(const PARCCryptoHash *parcDigest);
+
+/**
+ * Returnes the digest buffer, copy if you will destroy
+ *
+ * Returns the inner digest buffer. You must copy it if you will make
+ * changes or destroy it.
+ *
+ * @param [in] cryptoHash The `PARCCryptoHash` instance being examined.
+ *
+ * @return A `PARCBuffer` instance containing the raw hash digest.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = ...
+ * PARCCryptoHash *digest = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+ * PARCBuffer *rawDigest = parcCryptoHash_GetDigest(digest);
+ * // use the raw digest as necessary
+ * ...
+ * parcCryptoHash_Release(&digest);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcCryptoHash_GetDigest(const PARCCryptoHash *cryptoHash);
+
+/**
+ * Determine if two PARCCryptoHash instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCCryptoHash` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcCryptoHash_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcCryptoHash_Equals(x, y)` must return true if and only if
+ * parcCryptoHash_Equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcCryptoHash_Equals(x, y)` returns true and
+ * `parcCryptoHash_Equals(y, z)` returns true,
+ * then `parcCryptoHash_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcCryptoHash_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcCryptoHash_Equals(x, NULL)` must return false.
+ *
+ * @param [in] a A pointer to a PARCCryptoHash instance.
+ * @param [in] b A pointer to a PARCCryptoHash instance.
+ *
+ * @return True if the given PARCCryptoHash instances are equal, false otherwise.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = ...
+ * PARCCryptoHash *orig = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+ * PARCCryptoHash *copy = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+ *
+ * if (parcCryptoHash_Equals(orig, copy)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ *
+ * parcCryptoHash_Release(&orig);
+ * parcCryptoHash_Release(&copy);
+ * }
+ * @endcode
+ */
+bool parcCryptoHash_Equals(const PARCCryptoHash *a, const PARCCryptoHash *b);
+#endif // libparc_parc_CryptoHash_h
diff --git a/libparc/parc/security/parc_CryptoHashType.c b/libparc/parc/security/parc_CryptoHashType.c
new file mode 100644
index 00000000..78440f33
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoHashType.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_CryptoHashType.h>
+
+static struct {
+ PARCCryptoHashType type;
+ char *name;
+} cryptoHashType_ToString[] = {
+ { PARCCryptoHashType_SHA256, "PARCCryptoHashType_SHA256" },
+ { PARCCryptoHashType_SHA512, "PARCCryptoHashType_SHA512" },
+ { PARCCryptoHashType_CRC32C, "PARCCryptoHashType_CRC32C" },
+ { 0, NULL }
+};
+
+const char *
+parcCryptoHashType_ToString(PARCCryptoHashType type)
+{
+ for (int i = 0; cryptoHashType_ToString[i].name != NULL; i++) {
+ if (cryptoHashType_ToString[i].type == type) {
+ return cryptoHashType_ToString[i].name;
+ }
+ }
+ return NULL;
+}
+
+PARCCryptoHashType
+parcCryptoHashType_FromString(const char *name)
+{
+ for (int i = 0; cryptoHashType_ToString[i].name != NULL; i++) {
+ if (strcmp(cryptoHashType_ToString[i].name, name) == 0) {
+ return cryptoHashType_ToString[i].type;
+ }
+ }
+ return PARCCryptoHashType_NULL;
+}
diff --git a/libparc/parc/security/parc_CryptoHashType.h b/libparc/parc/security/parc_CryptoHashType.h
new file mode 100755
index 00000000..3ab1d9c9
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoHashType.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.
+ */
+
+/**
+ * @file parc_CryptoHashType.h
+ * @ingroup security
+ * @brief A type specifying a cryptographic hash (or CRC check) algorithm.
+ *
+ * This type is overloaded to support both cryptographic hash digest algorithms and cyclical-reduncancy
+ * check (CRC) algorithms. See the available `PARCCryptoHashType` enum types for an exhaustive
+ * list of the supported algorithms.
+ *
+ */
+#ifndef libparc_parc_CryptoHashType_h
+#define libparc_parc_CryptoHashType_h
+
+typedef enum {
+ PARCCryptoHashType_SHA256,
+ PARCCryptoHashType_SHA512,
+ PARCCryptoHashType_CRC32C,
+ PARCCryptoHashType_NULL
+} PARCCryptoHashType;
+
+/**
+ * Convert the `PARCCryptoHashType` value to a human-readable string representation.
+ *
+ * @param [in] type A `PARCCryptoHashType` value
+ *
+ * @return A static, null-terminated string.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHashType type = PARCCryptoHashType_SHA256;
+ * const char *stringRep = parcCryptoHashType_ToString(type);
+ * // use stringRep as necessary, and then free
+ * }
+ * @endcode
+ */
+const char *parcCryptoHashType_ToString(PARCCryptoHashType type);
+
+/**
+ * Convert a string representation value of a `PARCCryptoHashType` to an actual value.
+ *
+ * @param [in] name A string representation of a `PARCCryptoHashType` value.
+ *
+ * @return A `PARCCryptoHashType` value.
+ *
+ * Example:
+ * @code
+ * {
+ * const char stringRep[17] = "PARCCryptoHashType_SHA256";
+ * PARCCryptoHashType type = parcCryptoHashType_FromString(stringRep);
+ * // use stringRep as necessary, and then free
+ * }
+ * @endcode
+ */
+PARCCryptoHashType parcCryptoHashType_FromString(const char *name);
+#endif // libparc_parc_CryptoHashType_h
diff --git a/libparc/parc/security/parc_CryptoHasher.c b/libparc/parc/security/parc_CryptoHasher.c
new file mode 100755
index 00000000..f2c00967
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoHasher.c
@@ -0,0 +1,530 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 SHA256, and SHA512 with OpenSSL or Apple's CommonCrypto, depending on platform.
+ * It all follows the OpenSSL calling conventions:
+ * CTX_* is the digest's context
+ * INIT_* initializes the digest
+ * UPDATE_* updates the digest given a buffer
+ * FINAL_* finalizes the digest, returning the digest
+ * LENGTH_* is the byte length of the digest.
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#include <parc/security/parc_CryptoHasher.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Memory.h>
+#include <LongBow/runtime.h>
+#include <parc/algol/parc_Object.h>
+
+#ifdef __APPLE__
+#include <CommonCrypto/CommonDigest.h>
+
+#define CTX_SHA256 CC_SHA256_CTX
+#define INIT_SHA256 CC_SHA256_Init
+#define UPDATE_SHA256 CC_SHA256_Update
+#define FINAL_SHA256 CC_SHA256_Final
+#define LENGTH_SHA256 CC_SHA256_DIGEST_LENGTH
+
+#define CTX_SHA512 CC_SHA512_CTX
+#define INIT_SHA512 CC_SHA512_Init
+#define UPDATE_SHA512 CC_SHA512_Update
+#define FINAL_SHA512 CC_SHA512_Final
+#define LENGTH_SHA512 CC_SHA512_DIGEST_LENGTH
+
+#else
+#include <openssl/sha.h>
+#define CTX_SHA256 SHA256_CTX
+#define INIT_SHA256 SHA256_Init
+#define UPDATE_SHA256 SHA256_Update
+#define FINAL_SHA256 SHA256_Final
+#define LENGTH_SHA256 SHA256_DIGEST_LENGTH
+
+#define CTX_SHA512 SHA512_CTX
+#define INIT_SHA512 SHA512_Init
+#define UPDATE_SHA512 SHA512_Update
+#define FINAL_SHA512 SHA512_Final
+#define LENGTH_SHA512 SHA512_DIGEST_LENGTH
+#endif
+
+// -------------------------------------------------------------
+// function prototypes for use in the function structures
+static void *_sha256_create(void *env);
+static int _sha256_init(void *ctx);
+static int _sha256_update(void *ctx, const void *buffer, size_t length);
+static PARCBuffer *_sha256_finalize(void *ctx);
+static void _sha256_destroy(void **ctxPtr);
+
+static void *_sha512_create(void *env);
+static int _sha512_init(void *ctx);
+static int _sha512_update(void *ctx, const void *buffer, size_t length);
+static PARCBuffer *_sha512_finalize(void *ctx);
+static void _sha512_destroy(void **ctxPtr);
+
+static void *_crc32_create(void *env);
+static int _crc32_init(void *ctx);
+static int _crc32_update(void *ctx, const void *buffer, size_t length);
+static PARCBuffer *_crc32_finalize(void *ctx);
+static void _crc32_destroy(void **ctxPtr);
+// -------------------------------------------------------------
+
+// These are templates for the environments. SHA256 and SHA512 do not
+// have a functor_env, all the state is carried in the setup context.
+
+static PARCCryptoHasherInterface functor_sha256 = {
+ .functor_env = NULL,
+ .hasher_setup = _sha256_create,
+ .hasher_init = _sha256_init,
+ .hasher_update = _sha256_update,
+ .hasher_finalize = _sha256_finalize,
+ .hasher_destroy = _sha256_destroy
+};
+
+static PARCCryptoHasherInterface functor_sha512 = {
+ .functor_env = NULL,
+ .hasher_setup = _sha512_create,
+ .hasher_init = _sha512_init,
+ .hasher_update = _sha512_update,
+ .hasher_finalize = _sha512_finalize,
+ .hasher_destroy = _sha512_destroy
+};
+
+static PARCCryptoHasherInterface functor_crc32 = {
+ .functor_env = NULL,
+ .hasher_setup = _crc32_create,
+ .hasher_init = _crc32_init,
+ .hasher_update = _crc32_update,
+ .hasher_finalize = _crc32_finalize,
+ .hasher_destroy = _crc32_destroy
+};
+
+struct parc_crypto_hasher {
+ PARCCryptoHashType type;
+ PARCCryptoHasherInterface functor;
+ void *hasher_ctx;
+};
+
+static void
+_parcCryptoHasher_FinalRelease(PARCCryptoHasher **hasherP)
+{
+ PARCCryptoHasher *hasher = (PARCCryptoHasher *) *hasherP;
+ hasher->functor.hasher_destroy(&(hasher->hasher_ctx));
+}
+
+parcObject_ExtendPARCObject(PARCCryptoHasher, _parcCryptoHasher_FinalRelease, NULL, NULL, NULL, NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(parcCryptoHasher, PARCCryptoHasher);
+
+parcObject_ImplementRelease(parcCryptoHasher, PARCCryptoHasher);
+
+PARCCryptoHasher *
+parcCryptoHasher_Create(PARCCryptoHashType type)
+{
+ PARCCryptoHasher *hasher = parcObject_CreateInstance(PARCCryptoHasher);
+ assertNotNull(hasher, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCCryptoHasher));
+
+ hasher->type = type;
+
+ switch (type) {
+ case PARCCryptoHashType_SHA256:
+ hasher->functor = functor_sha256;
+ break;
+
+ case PARCCryptoHashType_SHA512:
+ hasher->functor = functor_sha512;
+ break;
+
+ case PARCCryptoHashType_CRC32C:
+ hasher->functor = functor_crc32;
+ break;
+
+ default:
+ parcMemory_Deallocate((void **) &hasher);
+ trapIllegalValue(type, "Unknown hasher type: %d", type);
+ }
+
+ hasher->hasher_ctx = hasher->functor.hasher_setup(hasher->functor.functor_env);
+ return hasher;
+}
+
+PARCCryptoHasher *
+parcCryptoHasher_CustomHasher(PARCCryptoHashType type, PARCCryptoHasherInterface functor)
+{
+ PARCCryptoHasher *hasher = parcObject_CreateInstance(PARCCryptoHasher);
+ assertNotNull(hasher, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(PARCCryptoHasher));
+ hasher->type = type;
+ hasher->functor = functor;
+ hasher->hasher_ctx = hasher->functor.hasher_setup(hasher->functor.functor_env);
+ return hasher;
+}
+
+/**
+ * Reset the internal state of the digest to start a new session
+ * Returns 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int
+parcCryptoHasher_Init(PARCCryptoHasher *digester)
+{
+ assertNotNull(digester, "Parameter must be non-null");
+
+ int success = digester->functor.hasher_init(digester->hasher_ctx);
+ return (success == 1) ? 0 : -1;
+}
+
+int
+parcCryptoHasher_UpdateBytes(PARCCryptoHasher *digester, const void *buffer, size_t length)
+{
+ assertNotNull(digester, "Parameter must be non-null");
+ int success = digester->functor.hasher_update(digester->hasher_ctx, buffer, length);
+ return (success == 1) ? 0 : -1;
+}
+
+int
+parcCryptoHasher_UpdateBuffer(PARCCryptoHasher *digester, const PARCBuffer *buffer)
+{
+ assertNotNull(digester, "Parameter must be non-null");
+ PARCBuffer *buf = parcBuffer_Slice(buffer);
+ size_t length = parcBuffer_Limit(buf);
+ void *byteArray = parcBuffer_Overlay(buf, length);
+ int success = digester->functor.hasher_update(digester->hasher_ctx, byteArray, length);
+
+ parcBuffer_Release(&buf);
+ return (success == 1) ? 0 : -1;
+}
+
+PARCCryptoHash *
+parcCryptoHasher_Finalize(PARCCryptoHasher *digester)
+{
+ assertNotNull(digester, "Parameter must be non-null");
+ PARCBuffer *digestBuffer = digester->functor.hasher_finalize(digester->hasher_ctx);
+
+ if (parcBuffer_Position(digestBuffer) != 0) {
+ parcBuffer_Flip(digestBuffer);
+ }
+
+ PARCCryptoHash *parcDigest = parcCryptoHash_Create(digester->type, digestBuffer);
+
+ parcBuffer_Release(&digestBuffer);
+ return parcDigest;
+}
+
+// ===============================================
+
+static void *
+_sha256_create(void *dummy)
+{
+ void *ctx = parcMemory_AllocateAndClear(sizeof(CTX_SHA256));
+ return ctx;
+}
+
+static int
+_sha256_init(void *ctx)
+{
+ return INIT_SHA256(ctx);
+}
+
+static int
+_sha256_update(void *ctx, const void *buffer, size_t length)
+{
+ return UPDATE_SHA256(ctx, buffer, (unsigned) length);
+}
+
+static PARCBuffer *
+_sha256_finalize(void *ctx)
+{
+ uint8_t buffer[LENGTH_SHA256];
+ FINAL_SHA256(buffer, ctx);
+
+ PARCBuffer *output = parcBuffer_Allocate(LENGTH_SHA256);
+ parcBuffer_PutArray(output, LENGTH_SHA256, buffer);
+
+ return output;
+}
+
+static void
+_sha256_destroy(void **ctxPtr)
+{
+ parcMemory_Deallocate((void **) ctxPtr);
+ *ctxPtr = NULL;
+}
+
+// ===============================================
+
+static void *
+_sha512_create(void *dummy)
+{
+ void *ctx = parcMemory_AllocateAndClear(sizeof(CTX_SHA512));
+ return ctx;
+}
+
+static int
+_sha512_init(void *ctx)
+{
+ return INIT_SHA512(ctx);
+}
+
+static int
+_sha512_update(void *ctx, const void *buffer, size_t length)
+{
+ return UPDATE_SHA512(ctx, buffer, (unsigned) length);
+}
+
+static PARCBuffer *
+_sha512_finalize(void *ctx)
+{
+ uint8_t buffer[LENGTH_SHA512];
+ FINAL_SHA512(buffer, ctx);
+
+ PARCBuffer *output = parcBuffer_Allocate(LENGTH_SHA512);
+ parcBuffer_PutArray(output, LENGTH_SHA512, buffer);
+
+ return output;
+}
+
+static void
+_sha512_destroy(void **ctxPtr)
+{
+ parcMemory_Deallocate((void **) ctxPtr);
+ *ctxPtr = NULL;
+}
+
+// ==================================================
+// CRC32C Implementation PARCCryptoHasher
+
+typedef struct crc32c_state {
+ uint32_t crc32;
+} _CRC32CState;
+
+// =====================================
+// Hardware calculation
+
+#ifdef __SSE4_2__
+#include <nmmintrin.h>
+
+#ifdef __x86_64__
+// The length rounded to 8-bytes
+#define CRC_ROUNDING_MASK 0xFFFFFFFFFFFFFFF8ULL
+#define LARGEST_CRC_INTRINSIC _mm_crc32_u64
+#define CRC_CAST_TYPE uint64_t
+#else
+// The length rounded to 4-bytes
+#define CRC_ROUNDING_MASK 0xFFFFFFFCUL
+#define LARGEST_CRC_INTRINSIC _mm_crc32_u32
+#define CRC_CAST_TYPE uint32_t
+#endif //__x86_64__
+
+static uint32_t
+_crc32c_UpdateIntel(uint32_t crc, size_t len, uint8_t p[len])
+{
+ size_t blocks = len & CRC_ROUNDING_MASK;
+ size_t offset = 0;
+
+ while (offset < blocks) {
+ crc = (uint32_t) LARGEST_CRC_INTRINSIC((CRC_CAST_TYPE) crc, *(CRC_CAST_TYPE *) &p[offset]);
+ offset += sizeof(CRC_CAST_TYPE);
+ }
+
+ // now do the last bytes if it was not 8-byte aligned
+ size_t position = blocks;
+ while (position < len) {
+ crc = _mm_crc32_u8((uint32_t) crc, p[position]);
+ position++;
+ }
+
+ return crc;
+}
+#endif
+
+// =====================================
+// Software calculation
+
+// Table generated from CRC Calculator http://sourceforge.net/projects/crccalculator/files/CRC/
+// The table is for bit-reversed bytes
+
+static const uint32_t _crc32c_table[] = {
+ 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
+ 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
+ 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
+ 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
+ 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
+ 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
+ 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
+ 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
+ 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
+ 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
+ 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
+ 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
+ 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
+ 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
+ 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
+ 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
+ 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
+ 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
+ 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
+ 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
+ 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
+ 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
+ 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
+ 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
+ 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
+ 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
+ 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
+ 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
+ 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
+ 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
+ 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
+ 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
+ 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
+ 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
+ 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
+ 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
+ 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
+ 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
+ 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
+ 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
+ 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
+ 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
+ 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
+ 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
+ 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
+ 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
+ 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
+ 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
+ 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
+ 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
+ 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
+ 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
+ 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
+ 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
+ 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
+ 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
+ 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
+ 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
+ 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
+ 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
+ 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
+ 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
+ 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
+ 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
+};
+
+/*
+ * If we use the hardware implementation, this function may be unused, but
+ * we keep it around for unit testing
+ */
+__attribute__((unused))
+static uint32_t
+_crc32c_UpdateSoftware(uint32_t crc, size_t len, uint8_t p[len])
+{
+ for (int i = 0; i < len; i++) {
+ crc = (crc >> 8) ^ _crc32c_table[((uint8_t) (crc & 0xFF)) ^ p[i]];
+ }
+
+ return crc;
+}
+
+/**
+ * Initializes the CRC32C value (init to 0xFFFFFFFF)
+ */
+static uint32_t
+_crc32c_Init(void)
+{
+ return ~0;
+}
+
+
+/**
+ * Finalizes the CRC32 (xor with 0xFFFFFFFF)
+ */
+static uint32_t
+_crc32c_Finalize(uint32_t crc)
+{
+ return crc ^ ~0;
+}
+
+/**
+ * Updates the CRC32 value with a byte array. Does
+ * bit mirroring to match either the Intel instruction set or
+ * the CRC table used by the software calculation.
+ */
+static uint32_t
+_crc32c_Update(uint32_t crc, size_t len, uint8_t p[len])
+{
+#ifdef __SSE4_2__
+ crc = _crc32c_UpdateIntel(crc, len, p);
+#else
+ crc = _crc32c_UpdateSoftware(crc, len, p);
+#endif
+ return crc;
+}
+
+/*
+ * Creates a new context variable for starting a hash
+ */
+static void *
+_crc32_create(void *env __attribute__ ((unused)))
+{
+ _CRC32CState *ctx = parcMemory_AllocateAndClear(sizeof(_CRC32CState));
+ assertNotNull(ctx, "parcMemory_AllocateAndClear(%zu) returned NULL for _CRC32CState", sizeof(_CRC32CState));
+
+ // Now initialize it with our digest and key, so in hmac_init we can avoid using those
+ return ctx;
+}
+
+static int
+_crc32_init(void *ctx)
+{
+ _CRC32CState *state = ctx;
+
+ // initialize the CRC32C with all 1's
+ state->crc32 = _crc32c_Init();
+
+ return 0;
+}
+
+static int
+_crc32_update(void *ctx, const void *buffer, size_t length)
+{
+ _CRC32CState *state = ctx;
+ state->crc32 = _crc32c_Update(state->crc32, length, (uint8_t *) buffer);
+ return 0;
+}
+
+static PARCBuffer *
+_crc32_finalize(void *ctx)
+{
+ _CRC32CState *state = ctx;
+ state->crc32 = _crc32c_Finalize(state->crc32);
+ PARCBuffer *crcDigest = parcBuffer_Allocate(sizeof(uint32_t));
+ parcBuffer_PutUint32(crcDigest, state->crc32);
+ return parcBuffer_Flip(crcDigest);
+}
+
+static void
+_crc32_destroy(void **ctxPtr)
+{
+ _CRC32CState *state = *ctxPtr;
+ parcMemory_Deallocate((void **) &state);
+ *ctxPtr = NULL;
+}
diff --git a/libparc/parc/security/parc_CryptoHasher.h b/libparc/parc/security/parc_CryptoHasher.h
new file mode 100755
index 00000000..2c93c1f7
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoHasher.h
@@ -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.
+ */
+
+/**
+ * @file parc_CryptoHasher.h
+ * @ingroup security
+ * @brief Computes digests of bytes or PARCBuffers.
+ *
+ * The PARCCryptoHasher computes digests of bytes or PARCBuffers.
+ * It produces a PARCCryptoHash (without the "er"), which contains the
+ * digest and the algorithm used to compute the digest.
+ *
+ */
+
+#ifndef libparc_parc_CryptoHasher_h
+#define libparc_parc_CryptoHasher_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/security/parc_CryptoHash.h>
+
+struct parc_crypto_hasher;
+typedef struct parc_crypto_hasher PARCCryptoHasher;
+
+typedef struct parc_crypto_hasher_interface {
+ void *functor_env;
+
+ /**
+ * Called with the environment and returns the setup context.
+ *
+ * @param [in] env The context environment (modified if needed).
+ */
+ void *(*hasher_setup)(void *env);
+
+ /**
+ * Setup the local context for the cryptographic hasher.
+ *
+ * These operate on the setup context, not the environment.
+ *
+ * @param [in] setup_ctx The local context that is initialized.
+ *
+ * @return 0 Successful initialization
+ * @return -1 An error occurred
+ */
+ int (*hasher_init)(void *setup_ctx);
+
+ /**
+ * Updated the digest using raw bytes
+ *
+ * @param [in] setup_ctx The local context for the hash digester
+ * @param [in] buffer Pointer to an array containing hte raw bytes used to update the digester
+ * @param [in] length Length of the input byte array
+ *
+ * @return 0 Successul update
+ * @return -1 An error occurred
+ */
+ int (*hasher_update)(void *setup_ctx, const void *buffer, size_t length);
+
+ /**
+ * Finalize the digest. Appends the digest to the output buffer, which
+ * the user must allocate.
+ *
+ * @param [in] setup_ctx The local context for the hash digester
+ *
+ * @return non-NULL A `PARCBuffer` containing the final hash digest.
+ * @return NULL An error ocurred
+ */
+ PARCBuffer* (*hasher_finalize)(void *setup_ctx);
+
+ /**
+ * Destroy the digester, releasing internal references as needed.
+ *
+ * @param [in] setup_ctx A pointer to a local context to destroy.
+ */
+ void (*hasher_destroy)(void **setup_ctx);
+} PARCCryptoHasherInterface;
+
+/**
+ * Create one of the pre-defined cryptographic hash "digesters" from the
+ * available `PARCCryptoHashType` types.
+ *
+ * @param [in] type A `PARCCryptoHashType` value.
+ *
+ * @return A newly allocated `PARCCryptoHasher` instance that must be freed by `parcCryptoHasher_Release()`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ * // initialize if needed
+ * // update bytes or finalize as needed
+ * parcCryptoHasher_Release(&digester);
+ * }
+ * @endcode
+ */
+PARCCryptoHasher *parcCryptoHasher_Create(PARCCryptoHashType type);
+
+
+/**
+ * Creates a custom hasher using the provided functor. Useful for
+ * implementing HMAC [RFC 2104] without leaking the key outside the keystore.
+ *
+ * The functor may carry an environment (i.e. info from the keystore) that will
+ * be echod back when CryptoHasher call the <code>functor->hasher_setup(functor->functor_env)</code>.
+ * All subsequent calls are passed the setup context
+ *
+ * Example:
+ * @code
+ * {
+ * static PARCCryptoHasherInterface hash_crc32c_template = {
+ * .functor_env = NULL,
+ * .hasher_setup = crc32cHasher_setup,
+ * .hasher_init = crc32cHasher_init,
+ * .hasher_update = crc32cHasher_update,
+ * .hasher_finalize= crc32cHasher_finalize,
+ * .hasher_destroy = crc32cHasher_destroy
+ * };
+ *
+ * CRC32CSigner *crc32Signer = parcMemory_AllocateAndClear(sizeof(CRC32CSigner));
+ * crc32Signer->hasher_functor = hash_crc32c_template;
+ * crc32Signer->hasher_functor.functor_env = crc32Signer;
+ * crc32Signer->hasher = parcCryptoHasher_CustomHasher(PARCCryptoHashType_CRC32C, crc32Signer->hasher_functor);
+ *
+ * PARCSigningInterface *signer = parcMemory_AllocateAndClear(sizeof(PARCSigningInterface));
+ * *signer = crc32signerimpl_template;
+ * signer->interfaceContext crc32Signer;
+ * return signer;
+ * }
+ * @endcode
+ */
+PARCCryptoHasher *parcCryptoHasher_CustomHasher(PARCCryptoHashType type, PARCCryptoHasherInterface functor);
+
+/**
+ * Increase the number of references to a `PARCCryptoHasher` instance.
+ *
+ * Note that a new `PARCCryptoHasher` is not created,
+ * only that the given `PARCCryptoHasher` reference count is incremented.
+ * Discard the reference by invoking {@link parcCryptoHasher_Release}.
+ *
+ * @param [in] hasher A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHasher *x = ...
+ * PARCCryptoHasher *x2 = parcCryptoHasher_Acquire(x);
+ *
+ * parcCryptoHasher_Release(&x);
+ * parcCryptoHasher_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see {@link parcCryptoHasher_Release}
+ */
+PARCCryptoHasher *parcCryptoHasher_Acquire(const PARCCryptoHasher *hasher);
+
+/**
+ * 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] hasherP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHasher *x = ...
+ *
+ * parcCryptoHasher_Release(&x);
+ * }
+ * @endcode
+ *
+ * @see {@link parcCryptoHasher_Acquire}
+ */
+void parcCryptoHasher_Release(PARCCryptoHasher **hasherP);
+
+/**
+ * Reset the internal state of the digest to start a new session.
+ *
+ * @param [in] digester A `PARCCryptoHasher` instance.
+ *
+ * @return 0 Successful reset
+ * @return -1 Some failure occurred
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ * parcCryptoHasher_Init(digester);
+ * // update bytes or finalize as needed
+ * parcCryptoHasher_Release(&digester);
+ * }
+ * @endcode
+ */
+int parcCryptoHasher_Init(PARCCryptoHasher *digester);
+
+/**
+ * Add bytes to the digest.
+ *
+ * @param [in] hasher A `PARCCryptoHasher` instance.
+ * @param [in] buffer A pointer to a raw buffer with bytes to update the hash digest.
+ * @param [in] length Length of the input byte array.
+ *
+ * @return 0 Successfully added bytes to the digest internally.
+ * @return -1 Some failure occurred
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ * parcCryptoHasher_Init(digester);
+ * ...
+ * uint8_t *buffer = ...
+ * size_t bufferLen = 32;
+ * parcCryptoHasher_UpdateBytes(digester, buffer, bufferLen);
+ * // update bytes or finalize as needed
+ * parcCryptoHasher_Release(&digester);
+ * }
+ * @endcode
+ */
+int parcCryptoHasher_UpdateBytes(PARCCryptoHasher *hasher, const void *buffer, size_t length);
+
+/**
+ * Add bytes to the digest. The bytes used are those starting at the
+ * specified buffer's "position" value.
+ *
+ * @param [in] hasher A `PARCCryptoHasher` instance.
+ * @param [in] buffer A `PARCBuffer` instance containing the bytes to add to the digest.
+ *
+ * @return 0 Successfully added bytes to the digest internally.
+ * @return -1 Some failure occurred
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ * parcCryptoHasher_Init(digester);
+ * ...
+ * PARCBuffer *buffer = ...
+ * parcCryptoHasher_UpdateBuffer(digester, buffer);
+ * // update bytes or finalize as needed
+ * parcCryptoHasher_Release(&digester);
+ * }
+ * @endcode
+ */
+int parcCryptoHasher_UpdateBuffer(PARCCryptoHasher *hasher, const PARCBuffer *buffer);
+
+/**
+ * Finalize the digest. Appends the digest to the output buffer, which
+ * the user must allocate.
+ *
+ * @param [in] hasher A `PARCCryptoHasher` instance.
+ *
+ * @return The output buffer - the final digest from the hash function computation.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ * parcCryptoHasher_Init(digester);
+ * ...
+ * PARCBuffer *buffer = ...
+ * parcCryptoHasher_UpdateBuffer(digester, buffer);
+ * PARCBuffer *hashDigest = parcCryptoHasher_Finalize(digester);
+ * // use the hashDigest as needed
+ * parcBuffer_Release(&hashDigest);
+ * parcCryptoHasher_Release(&digester);
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcCryptoHasher_Finalize(PARCCryptoHasher *hasher);
+
+/**
+ * Destroy the digester, releasing internal references as needed.
+ *
+ * @param [in] hasherPtr A pointer to a `PARCCryptoHasher` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ * parcCryptoHasher_Init(digester);
+ * ...
+ * parcCryptoHasher_Release(&digester);
+ * }
+ * @endcode
+ */
+void parcCryptoHasher_Release(PARCCryptoHasher **hasherPtr);
+#endif // libparc_parc_CryptoHasher_h
diff --git a/libparc/parc/security/parc_CryptoSuite.c b/libparc/parc/security/parc_CryptoSuite.c
new file mode 100755
index 00000000..43339121
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoSuite.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_CryptoSuite.h>
+#include <parc/security/parc_SigningAlgorithm.h>
+
+PARCCryptoHashType
+parcCryptoSuite_GetCryptoHash(PARCCryptoSuite suite)
+{
+ switch (suite) {
+ case PARCCryptoSuite_DSA_SHA256: // fallthrough
+ case PARCCryptoSuite_HMAC_SHA256: // fallthrough
+ case PARCCryptoSuite_RSA_SHA256: // fallthrough
+ case PARCCryptoSuite_ECDSA_SHA256:
+ return PARCCryptoHashType_SHA256;
+
+ case PARCCryptoSuite_HMAC_SHA512: // fallthrough
+ case PARCCryptoSuite_RSA_SHA512:
+ return PARCCryptoHashType_SHA512;
+
+ case PARCCryptoSuite_NULL_CRC32C:
+ return PARCCryptoHashType_CRC32C;
+
+ default:
+ trapIllegalValue(suite, "Unknown crypto suite: %d", suite);
+ }
+}
+
+int
+parcCryptoSuite_GetSignatureSizeBytes(PARCCryptoSuite suite, int keyLengthBits)
+{
+ int keyLengthBytes = keyLengthBits >> 3;
+ switch (suite) {
+ case PARCCryptoSuite_DSA_SHA256: // fallthrough
+ case PARCCryptoSuite_RSA_SHA256: // fallthrough
+ case PARCCryptoSuite_RSA_SHA512:
+ return keyLengthBytes;
+
+ case PARCCryptoSuite_ECDSA_SHA256:
+ return keyLengthBytes*2 + 8; //Overhead added by ECDSA
+
+ case PARCCryptoSuite_HMAC_SHA256: // fallthrough
+ case PARCCryptoSuite_HMAC_SHA512: // fallthrough
+ return 64;
+
+ case PARCCryptoSuite_NULL_CRC32C:
+ return 4;
+
+ default:
+ trapIllegalValue(suite, "Unknown crypto suite: %d", suite);
+ }
+}
+
+PARCCryptoSuite parcCryptoSuite_GetFromSigningHash(PARCSigningAlgorithm signAlgo, PARCCryptoHashType hash) {
+
+ switch (signAlgo) {
+ case PARCSigningAlgorithm_DSA:
+ return PARCCryptoSuite_DSA_SHA256 + hash;
+ case PARCSigningAlgorithm_RSA:
+ return PARCCryptoSuite_RSA_SHA256 + hash;
+ case PARCSigningAlgorithm_ECDSA:
+ return PARCCryptoSuite_ECDSA_SHA256 + hash;
+ case PARCSigningAlgorithm_NULL:
+ return PARCCryptoSuite_NULL_CRC32C;
+ default:
+ trapIllegalValue(suite, "Unknown signing algorithm suite: %d", signAlgo);
+ }
+}
+
+PARCSigningAlgorithm
+parcCryptoSuite_GetSigningAlgorithm(PARCCryptoSuite suite)
+{
+ switch (suite) {
+ case PARCCryptoSuite_DSA_SHA256:
+ return PARCSigningAlgorithm_DSA;
+
+ case PARCCryptoSuite_RSA_SHA256: // fallthrough
+ case PARCCryptoSuite_RSA_SHA512:
+ return PARCSigningAlgorithm_RSA;
+
+ case PARCCryptoSuite_HMAC_SHA256: // fallthrough
+ case PARCCryptoSuite_HMAC_SHA512:
+ return PARCSigningAlgorithm_HMAC;
+
+ case PARCCryptoSuite_ECDSA_SHA256:
+ return PARCSigningAlgorithm_ECDSA;
+ case PARCCryptoSuite_NULL_CRC32C:
+ return PARCSigningAlgorithm_NULL;
+
+ default:
+ trapIllegalValue(suit, "Unknown crypto suite: %d", suite);
+ }
+}
diff --git a/libparc/parc/security/parc_CryptoSuite.h b/libparc/parc/security/parc_CryptoSuite.h
new file mode 100755
index 00000000..366bcb11
--- /dev/null
+++ b/libparc/parc/security/parc_CryptoSuite.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 parc_CryptoSuite.h
+ * @ingroup security
+ * @brief Represent a cryptographic suite, a set of corresponding hash and signing/MAC/CRC algorithms.
+ *
+ * A cryptographic suite encapsulates the method by which (public key) digital signatures and
+ * (private key) MACs. For example, a digital signature suite might combine SHA-256 as the hash
+ * digest algorithm and RSA as the signature generation/verification algorithm. Such a suite
+ * would would have the PARCCryptoSuite value PARCCryptoSuite_RSA_SHA256.
+ *
+ */
+#ifndef libparc_parc_CryptoSuite_h
+#define libparc_parc_CryptoSuite_h
+
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_SigningAlgorithm.h>
+
+typedef enum {
+ PARCCryptoSuite_DSA_SHA256,
+ PARCCryptoSuite_DSA_SHA512,
+ PARCCryptoSuite_RSA_SHA256,
+ PARCCryptoSuite_RSA_SHA512,
+ PARCCryptoSuite_HMAC_SHA256,
+ PARCCryptoSuite_HMAC_SHA512,
+ PARCCryptoSuite_ECDSA_SHA256,
+ PARCCryptoSuite_ECDSA_SHA512,
+ PARCCryptoSuite_NULL_CRC32C,
+ PARCCryptoSuite_UNKNOWN
+} PARCCryptoSuite;
+
+/**
+ * Given a PARCCryptoSuite value, return the corresponding cryptographic hash as a `PARCCryptoHashType`.
+ *
+ * @param [in] suite A PARCCryptoSuite value.
+ *
+ * @return A PARCCryptoHashType value
+ *
+ * Example:
+ * @code
+ * {
+ * PARCryptoHashType hash = parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_RSA_SHA256);
+ * }
+ * @endcode
+ */
+PARCCryptoHashType parcCryptoSuite_GetCryptoHash(PARCCryptoSuite suite);
+
+/**
+ * Given a PARCCryptoSuite value and the key length, return the expected length in bytes of the signature.
+ * For ECDSA the result is the maximum length
+ *
+ * @param [in] suite A PARCCryptoSuite value.
+ *
+ * @return A PARCCryptoHashType value
+ *
+ * Example:
+ * @code
+ * {
+ * int bytes = parcCryptoSuite_GetSignatureSizeBits(PARCCryptoSuite_RSA_SHA256, 1024);
+ * }
+ * @endcode
+ */
+int parcCryptoSuite_GetSignatureSizeBytes(PARCCryptoSuite suite, int keyLengthBits);
+
+/**
+ * Given a PARCSigningAlgorithm value and a PARCCryptoHashType value, return the corresponding `PARCCryptoSuite`.
+ *
+ * @param [in] suite A PARCSigningAlgorithm value and a PARCCryptoHashType value
+ *
+ * @return A PARCCryptoSuite value
+ *
+ * Example:
+ * @code
+ * {
+ * PARCryptoSuite suite = parcCryptoSuite_GetFromSigningHash(PARCSigningAlgorihtm_RSA, PARCCryptoHashType_SHA256);
+ * }
+ * @endcode
+ */
+PARCCryptoSuite parcCryptoSuite_GetFromSigningHash(PARCSigningAlgorithm signAlgo, PARCCryptoHashType hash);
+
+/**
+ * Get the `PARCSigningAlgorithm` type associated with the specified `PARCCryptoSuite` type.
+ *
+ * PARCCryptoSuite types combine hash and signing algorithms to be used to signature and/or MAC generation.
+ * Therefore, a PARCCryptoSuite type of PARCCryptoSuite_DSA_SHA256, for example, uses the
+ * PARCSigningAlgorithm_DSA type of signing algorithm. This function serves to determine the
+ * signing algorithm type from the suite.
+ *
+ * @param [in] suite The type of cryptographic suite used for signature and/or MAC generation.
+ * @return A valid `PARCSigningAlgorithm` enum associated with the specified `PARCCryptoSuite` type.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCCryptoSuite suite = PARCCryptoSuite_RSA_SHA256;
+ * PARCSigningAlgorithm alg = parcSigningAlgorithm_GetSigningAlgorithm(suite);
+ * // do something with alg
+ * }
+ * @endcode
+ */
+PARCSigningAlgorithm parcCryptoSuite_GetSigningAlgorithm(PARCCryptoSuite suite);
+
+
+#endif // libparc_parc_CryptoSuite_h
diff --git a/libparc/parc/security/parc_DiffieHellman.c b/libparc/parc/security/parc_DiffieHellman.c
new file mode 100644
index 00000000..03edb0d9
--- /dev/null
+++ b/libparc/parc/security/parc_DiffieHellman.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 <parc/algol/parc_Object.h>
+
+#include <parc/security/parc_DiffieHellman.h>
+
+struct parc_diffie_hellman {
+ PARCDiffieHellmanGroup groupType;
+};
+
+static bool
+_parcDiffieHellman_Destructor(PARCDiffieHellman **pointer)
+{
+ return true;
+}
+
+parcObject_Override(PARCDiffieHellman, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcDiffieHellman_Destructor);
+
+parcObject_ImplementAcquire(parcDiffieHellman, PARCDiffieHellman);
+parcObject_ImplementRelease(parcDiffieHellman, PARCDiffieHellman);
+
+PARCDiffieHellman *
+parcDiffieHellman_Create(PARCDiffieHellmanGroup groupType)
+{
+ PARCDiffieHellman *dh = parcObject_CreateInstance(PARCDiffieHellman);
+
+ if (dh != NULL) {
+ dh->groupType = groupType;
+ }
+
+ return dh;
+}
+
+PARCDiffieHellmanKeyShare *
+parcDiffieHellman_GenerateKeyShare(PARCDiffieHellman *dh)
+{
+ return parcDiffieHellmanKeyShare_Create(dh->groupType);
+}
diff --git a/libparc/parc/security/parc_DiffieHellman.h b/libparc/parc/security/parc_DiffieHellman.h
new file mode 100644
index 00000000..b6a8c809
--- /dev/null
+++ b/libparc/parc/security/parc_DiffieHellman.h
@@ -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.
+ */
+
+/**
+ * @file parc_DiffieHellman.h
+ * @ingroup security
+ * @brief A factory for Diffie Hellman parameters.
+ *
+ */
+#ifndef libparc_parc_DiffieHellman_h
+#define libparc_parc_DiffieHellman_h
+
+#include <parc/security/parc_DiffieHellmanGroup.h>
+#include <parc/security/parc_DiffieHellmanKeyShare.h>
+
+struct parc_diffie_hellman;
+typedef struct parc_diffie_hellman PARCDiffieHellman;
+
+/**
+ * Create an instance of `PARCDiffieHellman.` that generates Diffie Hellman shares
+ * for the specified key exchange mechanisms.
+ *
+ * @param [in] groupType A type of PARCDiffieHellmanGroup
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a `PARCDiffieHellman` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDiffieHellman *dh = parcDiffieHellman_Create(PARCDiffieHellmanGroup_Secp521r1);
+ *
+ * parcDiffieHellman_Release(&dh);
+ * }
+ * @endcode
+ */
+PARCDiffieHellman *parcDiffieHellman_Create(PARCDiffieHellmanGroup groupType);
+
+/**
+ * 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 `parcDiffieHellman_Release()`.
+ *
+ * @param [in] dh A `PARCDiffieHellman` instance.
+ *
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCDiffieHellman *dh = parcDiffieHellman_Acquire(dhInstance);
+ *
+ * parcDiffieHellman_Release(&dh);
+ * }
+ * @endcode
+ *
+ * @see parcDiffieHellman_Release
+ */
+PARCDiffieHellman *parcDiffieHellman_Acquire(const PARCDiffieHellman *dh);
+
+/**
+ * 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] dhP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDiffieHellman *dh = parcDiffieHellman_Create(PARCDiffieHellmanGroup_Secp521r1);
+ *
+ * parcDiffieHellman_Release(&dh);
+ * }
+ * @endcode
+ */
+void parcDiffieHellman_Release(PARCDiffieHellman **dhP);
+
+/*
+ * Generate a fresh Diffie Hellman key share.
+ *
+ * @param [in] dh A `PARCDiffieHellman` instance.
+ *
+ * @return A `PARCDiffieHellmanKeyShare` instnace.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDiffieHellman *dh = parcDiffieHellman_Create(PARCDiffieHellmanGroup_Secp521r1);
+ *
+ * PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellman_GenerateKeyShare(dh);
+ * // use the key share
+ *
+ * parcDiffieHellmanKeyShare_Release(&keyShare);
+ * }
+ * @endcode
+ */
+PARCDiffieHellmanKeyShare *parcDiffieHellman_GenerateKeyShare(PARCDiffieHellman *dh);
+#endif // libparc_parc_DiffieHellman_h
diff --git a/libparc/parc/security/parc_DiffieHellmanGroup.h b/libparc/parc/security/parc_DiffieHellmanGroup.h
new file mode 100755
index 00000000..7402399e
--- /dev/null
+++ b/libparc/parc/security/parc_DiffieHellmanGroup.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 parc_DiffieHellmanGroup.h
+ * @ingroup security
+ * @brief An enumeration of the supported Diffie Hellman key exchange mechanisms.
+ *
+ */
+#ifndef libparc_parc_DiffieHellmanGroup_h
+#define libparc_parc_DiffieHellmanGroup_h
+
+typedef enum {
+ PARCDiffieHellmanGroup_Prime256v1, // NIST Prime-Curve P-256
+ PARCDiffieHellmanGroup_Secp521r1, // NIST Prime-Curve P-521
+ PARCDiffieHellmanGroup_Curve2559 // Curve2559
+} PARCDiffieHellmanGroup;
+
+#endif // libparc_parc_DiffieHellmanGroup_h
diff --git a/libparc/parc/security/parc_DiffieHellmanKeyShare.c b/libparc/parc/security/parc_DiffieHellmanKeyShare.c
new file mode 100644
index 00000000..250e5664
--- /dev/null
+++ b/libparc/parc/security/parc_DiffieHellmanKeyShare.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/security/parc_DiffieHellmanKeyShare.h>
+#include <parc/security/parc_CryptoHasher.h>
+#include <parc/security/parc_CryptoHash.h>
+
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+
+struct parc_diffie_hellman_keyshare {
+ PARCDiffieHellmanGroup groupType;
+ EVP_PKEY *privateKey;
+};
+
+static bool
+_parcDiffieHellmanKeyShare_Destructor(PARCDiffieHellmanKeyShare **pointer)
+{
+ PARCDiffieHellmanKeyShare *share = *pointer;
+
+ if (share->privateKey != NULL) {
+ EVP_PKEY_free(share->privateKey);
+ }
+
+ return true;
+}
+
+parcObject_Override(PARCDiffieHellmanKeyShare, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcDiffieHellmanKeyShare_Destructor);
+
+parcObject_ImplementAcquire(parcDiffieHellmanKeyShare, PARCDiffieHellmanKeyShare);
+parcObject_ImplementRelease(parcDiffieHellmanKeyShare, PARCDiffieHellmanKeyShare);
+
+static EVP_PKEY *
+_parcDiffieHellmanKeyShare_CreateShare(int curveid)
+{
+ EVP_PKEY_CTX *pctx;
+ EVP_PKEY_CTX *kctx;
+
+ pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+ if (pctx == NULL) {
+ return NULL;
+ }
+
+ int result = EVP_PKEY_paramgen_init(pctx);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(pctx);
+ return NULL;
+ }
+
+ result = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, curveid);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(pctx);
+ return NULL;
+ }
+
+ EVP_PKEY *params = NULL;
+ result = EVP_PKEY_paramgen(pctx, &params);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(pctx);
+ return NULL;
+ }
+
+ kctx = EVP_PKEY_CTX_new(params, NULL);
+ if (kctx == NULL) {
+ EVP_PKEY_CTX_free(pctx);
+ EVP_PKEY_free(params);
+ return NULL;
+ }
+
+ result = EVP_PKEY_keygen_init(kctx);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(pctx);
+ EVP_PKEY_free(params);
+ return NULL;
+ }
+
+ EVP_PKEY *pkey = NULL;
+ result = EVP_PKEY_keygen(kctx, &pkey);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(pctx);
+ EVP_PKEY_free(params);
+ EVP_PKEY_CTX_free(kctx);
+ return NULL;
+ }
+
+ EVP_PKEY_CTX_free(pctx);
+ EVP_PKEY_CTX_free(kctx);
+ EVP_PKEY_free(params);
+
+ return pkey;
+}
+
+PARCDiffieHellmanKeyShare *
+parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup groupType)
+{
+ PARCDiffieHellmanKeyShare *keyShare = parcObject_CreateInstance(PARCDiffieHellmanKeyShare);
+
+ if (keyShare != NULL) {
+ keyShare->groupType = groupType;
+
+ switch (groupType) {
+ case PARCDiffieHellmanGroup_Prime256v1:
+ keyShare->privateKey = _parcDiffieHellmanKeyShare_CreateShare(NID_X9_62_prime256v1);
+ break;
+ case PARCDiffieHellmanGroup_Secp521r1:
+ keyShare->privateKey = _parcDiffieHellmanKeyShare_CreateShare(NID_secp521r1);
+ break;
+ case PARCDiffieHellmanGroup_Curve2559:
+ default:
+ break;
+ }
+
+ if (keyShare->privateKey == NULL) {
+ assertTrue(false, "Unable to instantiate a private key.");
+ parcDiffieHellmanKeyShare_Release(&keyShare);
+ }
+ }
+
+ return keyShare;
+}
+
+PARCBuffer *
+parcDiffieHellmanKeyShare_SerializePublicKey(PARCDiffieHellmanKeyShare *keyShare)
+{
+ EC_KEY *ecKey = EVP_PKEY_get1_EC_KEY(keyShare->privateKey);
+
+ BN_CTX *bnctx = BN_CTX_new();
+ point_conversion_form_t form = EC_KEY_get_conv_form(ecKey);
+ const EC_POINT *point = EC_KEY_get0_public_key(ecKey);
+ const EC_GROUP *group = EC_KEY_get0_group(ecKey);
+ char *keyBuffer = EC_POINT_point2hex(group, point, form, bnctx);
+ int length = strlen(keyBuffer);
+
+ PARCBuffer *publicKey = parcBuffer_Allocate(length);
+ parcBuffer_PutArray(publicKey, length, (uint8_t *) keyBuffer);
+ parcBuffer_Flip(publicKey);
+
+ free(keyBuffer);
+ BN_CTX_free(bnctx);
+
+ return publicKey;
+}
+
+static EVP_PKEY *
+_parcDiffieHellman_DeserializePublicKeyShare(PARCDiffieHellmanKeyShare *keyShare, PARCBuffer *keyBuffer)
+{
+ EC_KEY *ecKey = EVP_PKEY_get1_EC_KEY(keyShare->privateKey);
+ const EC_GROUP *myGroup = EC_KEY_get0_group(ecKey);
+
+ EC_KEY *newKey = EC_KEY_new();
+ BN_CTX *newCtx = BN_CTX_new();
+ int result = EC_KEY_set_group(newKey, myGroup);
+ if (result != 1) {
+ BN_CTX_free(newCtx);
+ EC_KEY_free(newKey);
+ return NULL;
+ }
+
+ EC_POINT *newPoint = EC_POINT_new(myGroup);
+ char *keyString = parcBuffer_ToString(keyBuffer);
+ newPoint = EC_POINT_hex2point(myGroup, keyString, newPoint, newCtx);
+ if (newPoint == NULL) {
+ parcMemory_Deallocate(&keyString);
+ BN_CTX_free(newCtx);
+ EC_KEY_free(newKey);
+ EC_POINT_free(newPoint);
+ return NULL;
+ }
+
+ result = EC_KEY_set_public_key(newKey, newPoint);
+ if (result != 1) {
+ parcMemory_Deallocate(&keyString);
+ BN_CTX_free(newCtx);
+ EC_KEY_free(newKey);
+ EC_POINT_free(newPoint);
+ return NULL;
+ }
+
+ EVP_PKEY *peerkey = EVP_PKEY_new();
+ result = EVP_PKEY_set1_EC_KEY(peerkey, newKey);
+ if (result != 1) {
+ parcMemory_Deallocate(&keyString);
+ BN_CTX_free(newCtx);
+ EC_KEY_free(newKey);
+ EC_POINT_free(newPoint);
+ EVP_PKEY_free(peerkey);
+ return NULL;
+ }
+
+ BN_CTX_free(newCtx);
+ EC_KEY_free(newKey);
+ parcMemory_Deallocate((void **) &keyString);
+ EC_POINT_free(newPoint);
+
+ return peerkey;
+}
+
+static PARCBuffer *
+_parcDiffieHellmanKeyShare_HashSharedSecret(PARCBuffer *secret)
+{
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBuffer(hasher, secret);
+ PARCCryptoHash *digest = parcCryptoHasher_Finalize(hasher);
+
+ PARCBuffer *sharedSecret = parcBuffer_Acquire(parcCryptoHash_GetDigest(digest));
+
+ parcCryptoHash_Release(&digest);
+ parcCryptoHasher_Release(&hasher);
+
+ return sharedSecret;
+}
+
+PARCBuffer *
+parcDiffieHellmanKeyShare_Combine(PARCDiffieHellmanKeyShare *keyShare, PARCBuffer *theirs)
+{
+ EVP_PKEY *peerkey = _parcDiffieHellman_DeserializePublicKeyShare(keyShare, theirs);
+ if (peerkey == NULL) {
+ return NULL;
+ }
+
+ EVP_PKEY *privateKey = keyShare->privateKey;
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(privateKey, NULL);
+ if (ctx == NULL) {
+ EVP_PKEY_free(peerkey);
+ return NULL;
+ }
+
+ int result = EVP_PKEY_derive_init(ctx);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(peerkey);
+ return NULL;
+ }
+
+ result = EVP_PKEY_derive_set_peer(ctx, peerkey);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(peerkey);
+ return NULL;
+ }
+
+ size_t secretLength = 0;
+ result = EVP_PKEY_derive(ctx, NULL, &secretLength);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(peerkey);
+ return NULL;
+ }
+
+ unsigned char *secret = OPENSSL_malloc(secretLength);
+ if (secret == NULL) {
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(peerkey);
+ return NULL;
+ }
+
+ result = EVP_PKEY_derive(ctx, secret, &secretLength);
+ if (result != 1) {
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(peerkey);
+ OPENSSL_free(secret);
+ return NULL;
+ }
+
+ PARCBuffer *secretBuffer = parcBuffer_Allocate(secretLength);
+ parcBuffer_PutArray(secretBuffer, secretLength, secret);
+ parcBuffer_Flip(secretBuffer);
+
+ PARCBuffer *sharedSecret = _parcDiffieHellmanKeyShare_HashSharedSecret(secretBuffer);
+ parcBuffer_Release(&secretBuffer);
+
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(peerkey);
+ OPENSSL_free(secret);
+
+ return sharedSecret;
+}
diff --git a/libparc/parc/security/parc_DiffieHellmanKeyShare.h b/libparc/parc/security/parc_DiffieHellmanKeyShare.h
new file mode 100644
index 00000000..54e0f458
--- /dev/null
+++ b/libparc/parc/security/parc_DiffieHellmanKeyShare.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_DiffieHellmanKeyShare.h
+ * @ingroup security
+ * @brief A Diffie Hellman key share.
+ *
+ */
+#ifndef libparc_parc_DiffieHellmanKeyShare_h
+#define libparc_parc_DiffieHellmanKeyShare_h
+
+#include <parc/security/parc_DiffieHellmanGroup.h>
+
+struct parc_diffie_hellman_keyshare;
+typedef struct parc_diffie_hellman_keyshare PARCDiffieHellmanKeyShare;
+
+/**
+ * Create a `PARCDiffieHellmanKeyShare` instance to hold one public and private
+ * Diffie Hellman key share for the specified group.
+ *
+ * @param [in] groupType A type of PARCDiffieHellmanGroup
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a `PARCDiffieHellmanKeyShare` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ *
+ * parcDiffieHellmanKeyShare_Release(&keyShare);
+ * }
+ * @endcode
+ */
+PARCDiffieHellmanKeyShare *parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup groupType);
+
+/**
+ * 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 `parcDiffieHellman_Release()`.
+ *
+ * @param [in] keyShare A `PARCDiffieHellmanKeyShare` instance.
+ *
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Acquire(keyShareInstance);
+ *
+ * parcDiffieHellmanKeyShare_Release(&keyShare);
+ * }
+ * @endcode
+ *
+ * @see parcDiffieHellmanKeyShare_Release
+ */
+PARCDiffieHellmanKeyShare *parcDiffieHellmanKeyShare_Acquire(const PARCDiffieHellmanKeyShare *keyShare);
+
+/**
+ * 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] keyShareP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Acquire(keyShareInstance);
+ *
+ * parcDiffieHellmanKeyShare_Release(&keyShare);
+ * }
+ * @endcode
+ */
+void parcDiffieHellmanKeyShare_Release(PARCDiffieHellmanKeyShare **keyShareP);
+
+/**
+ * Serialize the public key part of a `PARCDiffieHellmanKeyShare.`
+ *
+ * The public key is saved to a `PARCBuffer` and can be used for transport if needed.
+ *
+ * @param [in] keyShare A `PARCDiffieHellmanKeyShare` instance.
+ *
+ * @return A `PARCBuffer` containing the public key of this key share.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ *
+ * PARCBuffer *publicKey = parcDiffieHellmanKeyShare_SerializePublicKey(keyShare);
+ * // use the public key
+ *
+ * parcBuffer_Release(&publicKey);
+ * parcDiffieHellmanKeyShare_Release(&keyShare);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcDiffieHellmanKeyShare_SerializePublicKey(PARCDiffieHellmanKeyShare *keyShare);
+
+/**
+ * Combine a `PARCDiffieHellmanKeyShare` with an encoded public key to create a shared secret.
+ *
+ * @param [in] keyShare A `PARCDiffieHellmanKeyShare` instance.
+ * @param [in] publicShare The public key share to use to derive the shared secrect.
+ *
+ * @return A `PARCBuffer` containing the shared secret from the Diffie Hellman exchange.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ *
+ * PARCBuffer *publicKey = parcDiffieHellmanKeyShare_SerializePublicKey(keyShare);
+ *
+ * ...
+ *
+ * PARCBuffer *sharedSecret = parcDiffieHellmanKeyShare_Combine(keyShare, publicKey);
+ * // use the shared secret to derive other cryptographic secrets.
+ *
+ * parcBuffer_Release(&sharedSecret);
+ * parcBuffer_Release(&publicKey);
+ * parcDiffieHellmanKeyShare_Release(&keyShare);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcDiffieHellmanKeyShare_Combine(PARCDiffieHellmanKeyShare *keyShare, PARCBuffer *publicShare);
+#endif // libparc_parc_DiffieHellmanKeyShare_h
diff --git a/libparc/parc/security/parc_Identity.c b/libparc/parc/security/parc_Identity.c
new file mode 100755
index 00000000..b48046ba
--- /dev/null
+++ b/libparc/parc/security/parc_Identity.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 <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/security/parc_Identity.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+struct parc_identity {
+ void *instance;
+ const PARCIdentityInterface *interface;
+};
+
+static void
+_parcIdentity_Destroy(PARCIdentity **identityPtr)
+{
+ PARCIdentity *identity = *identityPtr;
+
+ identity->interface->Release(&identity->instance);
+}
+
+parcObject_ExtendPARCObject(PARCIdentity, _parcIdentity_Destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+bool
+parcIdentity_IsValid(const PARCIdentity *identity)
+{
+ bool result = false;
+
+ if (identity != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+void
+parcIdentity_AssertValid(const PARCIdentity *identity)
+{
+ trapInvalidValueIf(parcIdentity_IsValid(identity) == false, "PARCIdentity");
+}
+
+PARCIdentity *
+parcIdentity_Create(PARCObject *instance, const PARCIdentityInterface *interface)
+{
+ assertNotNull(interface, "Got null interface in parcIdentity_Create");
+
+ PARCIdentity *result = parcObject_CreateInstance(PARCIdentity);
+
+ result->instance = parcObject_Acquire(instance);
+ result->interface = interface;
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcIdentity, PARCIdentity);
+
+parcObject_ImplementRelease(parcIdentity, PARCIdentity);
+
+bool
+parcIdentity_Equals(const PARCIdentity *a, const PARCIdentity *b)
+{
+ if (a == b) {
+ return true;
+ }
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+ return a->interface->Equals(a->instance, b->instance);
+}
+
+
+const char *
+parcIdentity_GetFileName(const PARCIdentity *identity)
+{
+ return identity->interface->GetFileName(identity->instance);
+}
+
+const char *
+parcIdentity_GetPassWord(const PARCIdentity *identity)
+{
+ return identity->interface->GetPassWord(identity->instance);
+}
+
+PARCSigner *
+parcIdentity_CreateSigner(const PARCIdentity *identity, PARCCryptoHashType hash)
+{
+ return identity->interface->GetSigner(identity->instance, hash);
+}
+
+void
+parcIdentity_Display(const PARCIdentity *identity, int indentation)
+{
+ assertNotNull(identity->interface->Display, "Got null implementation in parcIdentity_Display");
+
+ parcDisplayIndented_PrintLine(indentation, "PARCIdentity@%p {", identity);
+ parcDisplayIndented_PrintLine(indentation, ".instance=");
+ identity->interface->Display(identity->instance, 1);
+ parcDisplayIndented_PrintLine(indentation, "}\n");
+}
diff --git a/libparc/parc/security/parc_Identity.h b/libparc/parc/security/parc_Identity.h
new file mode 100755
index 00000000..c00af8fa
--- /dev/null
+++ b/libparc/parc/security/parc_Identity.h
@@ -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.
+ */
+
+/**
+ * @file parc_Identity.h
+ * @ingroup security
+ * @brief A generic cryptographic identity that is assigned to an entity
+ * (user, group, process) and is associated with a set of cryptographic
+ * material, e.g., public and private keys.
+ *
+ * Identities are used for authentication and authorization purposes.
+ * To illustrate their use, consider the following model. Digital signatures
+ * are computed with a private key owned by some entity. This private
+ * key is associated with an identity. It is said that the digital signature
+ * in this case was procured by an entity with the identity associated
+ * with the private key. Moreover, verifying this digital signature with
+ * the corresponding public key is analogous to verifying that the signature
+ * was generated by an entity with the corresponding identity.
+ *
+ * The relationship between identities and entities means that an entity may have
+ * multiple identities, each of which is associated with its own set of cryptographic
+ * information.
+ *
+ * Finally, an identity is typically backed by a file which stores the set of
+ * cryptographic material. For instance, once an identity may be represented as a
+ * PKCS12 (public and private) key store. Other concrete identity implementations
+ * may have different backing stores (i.e., not files, but services) with
+ * different notions of secret passwords.
+ *
+ */
+#ifndef libparc_parc_Identity_h
+#define libparc_parc_Identity_h
+
+#include <parc/algol/parc_Object.h>
+#include <parc/security/parc_Signer.h>
+#include <parc/security/parc_CryptoHashType.h>
+
+struct parc_identity;
+typedef struct parc_identity PARCIdentity;
+
+typedef struct parc_identity_interface {
+ /**
+ * @see parcIdentity_Acquire
+ */
+ PARCIdentity *(*Acquire)(void *identity);
+
+ /**
+ * @see parcIdentity_Release
+ */
+ void (*Release)(void **identityPtr);
+
+ /**
+ * @see parcIdentity_GetPassWord
+ */
+ void *(*GetPassWord)(const void *original);
+
+ /**
+ * @see parcIdentity_GetFileName
+ */
+ void *(*GetFileName)(const void *original);
+
+ /**
+ * @see parcIdentity_CreateSigner
+ */
+ PARCSigner *(*GetSigner)(const void *identity, PARCCryptoHashType hash);
+
+ /**
+ * @see parcIdentity_Equals
+ */
+ bool (*Equals)(const void *a, const void *b);
+
+ /**
+ * @see `parcIdentity_Display`
+ */
+ void (*Display)(const void *identity, size_t indentation);
+} PARCIdentityInterface;
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcIdentity_OptionalAssertValid(_instance_)
+#else
+# define parcIdentity_OptionalAssertValid(_instance_) parcIdentity_AssertValid(_instance_)
+#endif
+
+/**
+ * Determine if an instance of `PARCIdentity` 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] identity A pointer to a `PARCIdentity` instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *instance = parcIdentity_Create();
+ *
+ * if (parcIdentity_IsValid(instance)) {
+ * printf("Instance is valid.\n");
+ * }
+ * }
+ * @endcode
+ */
+bool parcIdentity_IsValid(const PARCIdentity *identity);
+
+/**
+ * Assert that the given `PARCIdentity` instance is valid.
+ *
+ * @param [in] identity A pointer to a valid PARCIdentity instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *a = parcIdentity_Create();
+ *
+ * parcIdentity_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcIdentity_Release(&b);
+ * }
+ * @endcode
+ */
+void parcIdentity_AssertValid(const PARCIdentity *identity);
+
+/**
+ * Create an instance of PARCIdentity from the given pointer to a subtype
+ * and the subtype's `PARCIdentityInterface` instance.
+ *
+ * A new reference to @p instance is acquired.
+ *
+ * @param [in] instance A pointer to a suitable subtype of `PARCIdentity`.
+ * @param [in] interface A poitner to the subtype's `PARCIdentityInterface` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a `PARCIdentity` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *identity = parcIdentity_Create(...);
+ *
+ * parcIdentity_Release(&identity);
+ * }
+ * @endcode
+ */
+PARCIdentity *parcIdentity_Create(PARCObject *instance, const PARCIdentityInterface *interface);
+
+/**
+ * Increase the number of references to a `PARCIdentity` instance.
+ *
+ * Note that new `PARCIdentity` is not created,
+ * only that the given `PARCIdentity` reference count is incremented.
+ * Discard the reference by invoking `parcIdentity_Release`.
+ *
+ * @param [in] identity A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *identity = parcIdentity_Create(...);
+ * PARCIdentity *i2 = parcIdentity_Acquire(identity);
+ * // use both as needed
+ * parcIdentity_Release(&i2);
+ * parcIdentity_Release(&identity);
+ * }
+ * @endcode
+ *
+ * @see parcIdentity_Release
+ */
+PARCIdentity *parcIdentity_Acquire(const PARCIdentity *identity);
+
+/**
+ * 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] identityPtr A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *identity = parcIdentity_Create(...);
+ *
+ * parcIdentity_Release(&identity);
+ * }
+ * @endcode
+ */
+void parcIdentity_Release(PARCIdentity **identityPtr);
+
+/**
+ * Retrieve the file name associated with this identity.
+ *
+ * In the case of an identity file, this is the actual file name.
+ * Other concrete identity implementations may have different notions of secret passwords.
+ *
+ * NOTE: This function is set to be removed from the PARCIdentity API.
+ *
+ * @param [in] identity A `PARCIdentity` instance.
+ *
+ * @return A nul-terminated string containing the file name.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *identity = parcIdentity_Create(...);
+ * char *fileName = parcIdentity_GetFileName(identity);
+ * // use the filename
+ * parcIdentity_Release(&identity);
+ * }
+ * @endcode
+ */
+const char *parcIdentity_GetFileName(const PARCIdentity *identity);
+
+/**
+ * Retrieve the secret password associated with this identity..
+ *
+ * In the case of an identity file, the password will be one that opens the file for access.
+ * Other concrete identity implementations may have different notions of secret passwords.
+ *
+ * NOTE: This function is set to be removed from the PARCIdentity API.
+ *
+ * @param [in] identity A `PARCIdentity` instance.
+ *
+ * @return A character array containing the identity password.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *identity = parcIdentity_Create(...);
+ * char *pw = parcIdentity_GetPassWord(identity);
+ * // use the password pw
+ * parcIdentity_Release(&identity);
+ * }
+ * @endcode
+ */
+const char *parcIdentity_GetPassWord(const PARCIdentity *identity);
+
+/**
+ * Create an instance of `PARCSigner` from the given `PARCIdentity`.
+ *
+ * The `PARCSigner` instance must be released via `parcSignature_Release()`.
+ *
+ * @param [in] identity A pointer to a PARCIdentity instance.
+ *
+ * @return PARCSigner A newly allocated `PARCSigner` instance based off this identity.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *identity = parcIdentity_Create(...);
+ * PARCSigner *signer = parcIdentity_CreateSigner(identity);
+ *
+ * // use the signer as needed...
+ *
+ * parcSigner_Release(&signer);
+ * parcIdentity_Release(&identity);
+ * }
+ * @endcode
+ */
+PARCSigner *parcIdentity_CreateSigner(const PARCIdentity *identity, PARCCryptoHashType hash);
+
+/**
+ * Determine if two PARCIdentity are equal.
+ *
+ * The following equivalence relations on non-null `XXX` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, parcIdentity_Equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, PARCIdentity_Equals(x, y) must return true if and only if
+ * parcIdentity_Equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * parcIdentity_Equals(x, y) returns true and
+ * parcIdentity_Equals(y, z) returns true,
+ * then parcIdentity_Equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of parcIdentity_Equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, parcIdentity_Equals(x, NULL)) must return false.
+ *
+ * @param a A pointer to a PARCIdentity instance.
+ * @param b A pointer to a PARCIdentity instance.
+ * @return True if the referenced PARCIdentity are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *a = parcIdentity_Create(...);
+ * PARCIdentity *b = parcIdentity_Create(...);
+ * parcIdentity_Equals(a, b)
+ * if (parcIdentity_Equals(a, b)) {
+ * // this is expected
+ * } else {
+ * // this is not expected
+ * }
+ * parcIdentity_Release(&a);
+ * parcIdentity_Release(&b);
+ * }
+ * @endcode
+ */
+bool parcIdentity_Equals(const PARCIdentity *a, const PARCIdentity *b);
+
+/**
+ * Print a human readable representation of the given `PARCIdentity`.
+ *
+ * @param [in] identity A pointer to the instance to display.
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentity *instance = parcIdentity_Create(...);
+ *
+ * parcIdentity_Display(instance, 0);
+ *
+ * parcIdentity_Release(&instance);
+ * }
+ * @endcode
+ */
+void parcIdentity_Display(const PARCIdentity *identity, int indentation);
+#endif // libparc_parc_Identity_h
diff --git a/libparc/parc/security/parc_IdentityFile.c b/libparc/parc/security/parc_IdentityFile.c
new file mode 100644
index 00000000..0d22a51e
--- /dev/null
+++ b/libparc/parc/security/parc_IdentityFile.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 <LongBow/runtime.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <parc/security/parc_Identity.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_PublicKeySigner.h>
+
+#include <parc/security/parc_IdentityFile.h>
+
+struct parc_identity_file {
+ const char *fileName;
+ const char *passWord;
+};
+
+PARCIdentityInterface *PARCIdentityFileAsPARCIdentity = &(PARCIdentityInterface) {
+ .Acquire = (PARCIdentity * (*)(void *))parcIdentityFile_Acquire,
+ .Release = (void (*)(void **))parcIdentityFile_Release,
+ .GetPassWord = (void *(*)(const void *))parcIdentityFile_GetPassWord,
+ .GetFileName = (void *(*)(const void *))parcIdentityFile_GetFileName,
+ .GetSigner = (PARCSigner * (*)(const void *, PARCCryptoHashType))parcIdentityFile_CreateSigner,
+ .Equals = (bool (*)(const void *, const void *))parcIdentityFile_Equals,
+ .Display = (void (*)(const void *, size_t))parcIdentityFile_Display
+};
+
+void static
+_finalize(PARCIdentityFile **IdentityPtr)
+{
+ PARCIdentityFile *identity = *IdentityPtr;
+ parcMemory_Deallocate((void **) &(identity->fileName));
+ parcMemory_Deallocate((void **) &(identity->passWord));
+}
+
+
+parcObject_ExtendPARCObject(PARCIdentityFile, _finalize, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCIdentityFile *
+parcIdentityFile_Create(const char *fileName, const char *passWord)
+{
+ PARCIdentityFile *instance = parcObject_CreateInstance(PARCIdentityFile);
+
+ if (instance != NULL) {
+ instance->fileName = parcMemory_StringDuplicate(fileName, strlen(fileName));
+ instance->passWord = parcMemory_StringDuplicate(passWord, strlen(passWord));
+ }
+
+ return instance;
+}
+
+parcObject_ImplementAcquire(parcIdentityFile, PARCIdentityFile);
+
+parcObject_ImplementRelease(parcIdentityFile, PARCIdentityFile);
+
+bool
+parcIdentityFile_Exists(const PARCIdentityFile *identity)
+{
+ bool result = false;
+
+ struct stat statbuf;
+
+ if (stat(parcIdentityFile_GetFileName(identity), &statbuf) != -1) {
+ if (S_ISREG(statbuf.st_mode)) {
+ result = (access(parcIdentityFile_GetFileName(identity), F_OK | R_OK) == 0);
+ }
+ }
+
+ return result;
+}
+
+const char *
+parcIdentityFile_GetFileName(const PARCIdentityFile *identity)
+{
+ return identity->fileName;
+}
+
+const char *
+parcIdentityFile_GetPassWord(const PARCIdentityFile *identity)
+{
+ return identity->passWord;
+}
+
+PARCSigner *
+parcIdentityFile_CreateSigner(const PARCIdentityFile *identity, PARCCryptoHashType hash)
+{
+ PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open(identity->fileName, identity->passWord, PARCCryptoHashType_SHA256);
+ PARCKeyStore *publicKeyStore = parcKeyStore_Create(keyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&keyStore);
+
+ PARCSigningAlgorithm signAlgo = parcKeyStore_getSigningAlgorithm(publicKeyStore);
+
+ PARCCryptoSuite suite = parcCryptoSuite_GetFromSigningHash(signAlgo, hash);
+
+ PARCPublicKeySigner *signer = parcPublicKeySigner_Create(publicKeyStore, suite);
+ PARCSigner *pkSigner = parcSigner_Create(signer, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&signer);
+ parcKeyStore_Release(&publicKeyStore);
+
+ return pkSigner;
+}
+
+bool
+parcIdentityFile_Equals(const PARCIdentityFile *a, const PARCIdentityFile *b)
+{
+ if (a == b) {
+ return true;
+ }
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+ if (strcmp(parcIdentityFile_GetFileName(a), parcIdentityFile_GetFileName(b)) != 0) {
+ return false;
+ }
+ if (strcmp(parcIdentityFile_GetPassWord(a), parcIdentityFile_GetPassWord(b)) != 0) {
+ return false;
+ }
+ return true;
+}
+
+void
+parcIdentityFile_Display(const PARCIdentityFile *instance, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation, "PARCIdentityFile@%p {", instance);
+ parcDisplayIndented_PrintLine(indentation + 1, ".fileName='%s', .passWord='%s'", instance->fileName, instance->passWord);
+ parcDisplayIndented_PrintLine(indentation, "}", instance);
+}
diff --git a/libparc/parc/security/parc_IdentityFile.h b/libparc/parc/security/parc_IdentityFile.h
new file mode 100644
index 00000000..46ff87cb
--- /dev/null
+++ b/libparc/parc/security/parc_IdentityFile.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_IdentityFile.h
+ * @ingroup security
+ * @brief This is a PARCIdentity represented as a PKCS12 keystore file.
+ *
+ * To create these files, use the `parc-publickey` command line tool. Or you could also
+ * use `openssl` to create the same file.
+ *
+ * A `PARCIdentityFile` is a concrete instance of a `PARCIdentity`. To create a
+ * `PARCIdentity` from a `PARCIdentityFile`, one would do the following:
+ *
+ * @code
+ * {
+ * const char *keystoreName = "my_identity.p12";
+ * const char *keystorePassword = "my_password";
+ *
+ * // Create the concrete identity instance from the PKCS12 file
+ * PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+ *
+ * // Create a generic `PARCIdentity` from the concrete identity instance
+ * PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ *
+ * // Now use the `PARCIdentity` for signing purposes (amongst other things)
+ * PARCSigner *signer = parcIdentity_GetSigner(identity);
+ * }
+ * @endcode
+ *
+ */
+#ifndef libparc_parc_IdentityFile_h
+#define libparc_parc_IdentityFile_h
+
+#include <parc/security/parc_Identity.h>
+
+struct parc_identity_file;
+typedef struct parc_identity_file PARCIdentityFile;
+
+/**
+ * The mapping of a PARCIdentityFile to the generic PARCIdentity.
+ */
+extern PARCIdentityInterface *PARCIdentityFileAsPARCIdentity;
+
+/**
+ * Create an instance of `PARCIdentityFile` from a given filename, and a password to unlock the stored information.
+ *
+ * The information is stored in PKCS 12 format.
+ *
+ * @param [in] fileName The name (relative path) to a file to be opened
+ * @param [in] password The password to be used to open the identity file
+ *
+ * @return NULL A `PARCIdentityFile` could not be allocated.
+ * @return PARCIdentityFile A newly allocated `PARCIdentityFile` that must be freed with `parcIdentityFile_Release()`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *file = parcIdentityFile_Create("./secret.p12", "1234");
+ * ...
+ * parcIdentityFile_Release(&file);
+ * }
+ * @endcode
+ */
+PARCIdentityFile *parcIdentityFile_Create(const char *fileName, const char *password);
+
+/**
+ * Increase the number of references to the given `PARCIdentityFile` instance.
+ *
+ * A new instance is not created,
+ * only that the given instance's reference count is incremented.
+ * Discard the acquired reference by invoking `parcIdentityFile_Release()`.
+ *
+ * @param [in] identity A pointer to a `PARCIdentityFile` instance.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a PARCIdentityFile instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *file = parcIdentityFile_Create("./secret.p12", "1234");
+ * PARCIdentityFile *secondHandle = parcIdentityFile_Acquire(file);
+ * // use both handles as needed
+ * parcIdentityFile_Release(&file);
+ * parcIdentityFile_Release(&secondHandle);
+ * }
+ * @endcode
+ */
+PARCIdentityFile *parcIdentityFile_Acquire(const PARCIdentityFile *identity);
+
+/**
+ * Decrease the number of references to the given `PARCIdentityFile` instance.
+ *
+ * This only decrements the reference count so long as count >= 1. If the count
+ * reaches zero, the object's memory is freed. The content pointer is always
+ * NULLified after invocation.
+ *
+ * @param [in,out] identityPtr A pointer to a `PARCIdentityFile` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *file = parcIdentityFile_Create("./secret.p12", "1234");
+ * // use handle as needed
+ * parcIdentityFile_Release(&file);
+ * }
+ * @endcode
+ */
+void parcIdentityFile_Release(PARCIdentityFile **identityPtr);
+
+/**
+ * Determine if the PARCIdentityFile exists.
+ *
+ * It must exist and be a regular file.
+ *
+ * @param [in] identity A pointer to a valid PARCIdentity instance.
+ *
+ * @return true The file exists and is a regular file.
+ * @return false The file does not exist (see errno values for stat(2)) or is not a regular file.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *file = parcIdentityFile_Create("./secret.p12", "1234");
+ *
+ * if (parcIdentityFile_Exists(file) == true) {
+ * printf("The file exists\n");
+ * } else {
+ * printf("The file does not exist fos\n");
+ * }
+ * }
+ * @endcode
+ */
+bool parcIdentityFile_Exists(const PARCIdentityFile *identity);
+
+/**
+ * Retrieve the name of the file associated with this `PARCIdentityFile` instance.
+ *
+ * @param [in] identity A pointer to a `PARCIdentityFile` instance.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a PARCIdentityFile instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *file = parcIdentityFile_Create("./secret.p12", "1234");
+ * const char *fileName = parcIdentityFile_GetFileName(file);
+ * // use handle and/or file name as needed
+ * parcIdentityFile_Release(&file);
+ * }
+ * @endcode
+ */
+const char *parcIdentityFile_GetFileName(const PARCIdentityFile *identity);
+
+/**
+ * Retrieve the file password associated with this `PARCIdentityFile` instance.
+ *
+ * @param [in] identity A pointer to a `PARCIdentityFile` instance.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a PARCIdentityFile instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *file = parcIdentityFile_Create("./secret.p12", "1234");
+ * const char *password = parcIdentityFile_GetPassWord(file);
+ * // use handle and/or file name as needed
+ * parcIdentityFile_Release(&file);
+ * }
+ * @endcode
+ */
+const char *parcIdentityFile_GetPassWord(const PARCIdentityFile *identity);
+
+/**
+ * Create an instance of `PARCSigner` from the given `PARCIdentity`
+ *
+ * @param [in] identity A pointer to a PARCIdentity instance.
+ *
+ * @return NULL An error occurred
+ * @return PARCSigner A new `PARCSigner` instance created using the identity file for the public/private signing keys
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *file = parcIdentityFile_Create("./secret.p12", "1234");
+ * PARCSigner *signer = parcIdentityFile_GetSigner(file);
+ * parcIdentityFile_Release(&file);
+ * // use the signer
+ * parcSigner_Release(&signer);
+ * }
+ * @endcode
+ */
+PARCSigner *parcIdentityFile_CreateSigner(const PARCIdentityFile *identity, PARCCryptoHashType hash);
+
+/**
+ * Determine if two PARCIdentityFiles are equal.
+ *
+ * The following equivalence relations on non-null `PARCIdentityFile` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, parcIdentityFile_Equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, parcIdentityFile_Equals(x, y) must return true if and only if
+ * parcIdentityFile_Equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * parcIdentityFile_Equals(x, y) returns true and
+ * parcIdentityFile_Equals(y, z) returns true,
+ * then parcIdentityFile_Equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of parcIdentityFile_Equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, parcIdentityFile_Equals(x, NULL)) must return false.
+ *
+ * @param a A pointer to a PARCIdentityFile instance.
+ * @param b A pointer to a PARCIdentityFile instance.
+ * @return True if the referenced PARCIdentityFiles are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *a = parcIdentityFile_Create(...);
+ * PARCIdentityFile *b = parcIdentityFile_Create(...);
+ * if (parcIdentityFile_Equals(a, b)) {
+ * // this is expected
+ * } else {
+ * // this is not expected
+ * }
+ * parcIdentityFile_Release(&a);
+ * parcIdentityFile_Release(&b);
+ * }
+ *
+ * }
+ * @endcode
+ */
+bool parcIdentityFile_Equals(const PARCIdentityFile *a, const PARCIdentityFile *b);
+
+/**
+ * Print a human readable representation of the given `PARCIdentityFile`.
+ *
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ * @param [in] instance A pointer to the instance to display.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCIdentityFile *instance = parcIdentityFile_Create("./secret.p12", "1234");
+ *
+ * parcIdentityFile_Display(instance, 0);
+ *
+ * parcIdentityFile_Release(&instance);
+ * }
+ * @endcode
+ */
+void parcIdentityFile_Display(const PARCIdentityFile *instance, int indentation);
+#endif // libparc_parc_IdentityFile_h
diff --git a/libparc/parc/security/parc_InMemoryVerifier.c b/libparc/parc/security/parc_InMemoryVerifier.c
new file mode 100644
index 00000000..c3af4d7d
--- /dev/null
+++ b/libparc/parc/security/parc_InMemoryVerifier.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_InMemoryVerifier.c
+ * <#Abstract#>
+ *
+ * <#Discussion#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#include <config.h>
+#include <stdio.h>
+
+#include <LongBow/runtime.h>
+#include <parc/security/parc_InMemoryVerifier.h>
+#include <parc/security/parc_CryptoHasher.h>
+#include <parc/security/parc_CryptoCache.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <openssl/x509v3.h>
+#include <openssl/ecdsa.h>
+
+
+struct parc_inmemory_verifier {
+ PARCCryptoHasher *hasher_sha256;
+ PARCCryptoHasher *hasher_sha512;
+ PARCCryptoCache *key_cache;
+};
+
+static bool
+_parcInMemoryVerifier_Destructor(PARCInMemoryVerifier **verifierPtr)
+{
+ PARCInMemoryVerifier *verifier = *verifierPtr;
+
+ parcCryptoHasher_Release(&(verifier->hasher_sha256));
+ parcCryptoHasher_Release(&(verifier->hasher_sha512));
+ parcCryptoCache_Destroy(&(verifier->key_cache));
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcInMemoryVerifier, PARCInMemoryVerifier);
+parcObject_ImplementRelease(parcInMemoryVerifier, PARCInMemoryVerifier);
+
+parcObject_Override(PARCInMemoryVerifier, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcInMemoryVerifier_Destructor);
+
+PARCInMemoryVerifier *
+parcInMemoryVerifier_Create()
+{
+ PARCInMemoryVerifier *verifier = parcObject_CreateInstance(PARCInMemoryVerifier);
+ if (verifier != NULL) {
+ // right now only support sha-256. need to figure out how to make this flexible
+ verifier->hasher_sha256 = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ verifier->hasher_sha512 = parcCryptoHasher_Create(PARCCryptoHashType_SHA512);
+ verifier->key_cache = parcCryptoCache_Create();
+ }
+
+ return verifier;
+}
+
+
+// ======================================
+
+static PARCCryptoHasher *
+_parcInMemoryVerifier_GetCryptoHasher(void *interfaceContext, PARCKeyId *keyid, PARCCryptoHashType hashType)
+{
+ PARCInMemoryVerifier *verifier = (PARCInMemoryVerifier *) interfaceContext;
+
+ const PARCKey *key = parcCryptoCache_GetKey(verifier->key_cache, keyid);
+ if (key == NULL) {
+ return false;
+ }
+
+ assertFalse(parcKey_GetSigningAlgorithm(key) == PARCSigningAlgorithm_HMAC, "HMAC not supported yet");
+
+ switch (hashType) {
+ case PARCCryptoHashType_SHA256:
+ return verifier->hasher_sha256;
+
+ case PARCCryptoHashType_SHA512:
+ return verifier->hasher_sha512;
+
+ default:
+ trapUnexpectedState("unsupported hash type: %d", hashType);
+ }
+}
+
+static bool
+_parcInMemoryVerifier_AllowedCryptoSuite(void *interfaceContext, PARCKeyId *keyid, PARCCryptoSuite suite)
+{
+ PARCInMemoryVerifier *verifier = (PARCInMemoryVerifier *) interfaceContext;
+
+ const PARCKey *key = parcCryptoCache_GetKey(verifier->key_cache, keyid);
+ if (key == NULL) {
+ return false;
+ }
+
+ switch (parcKey_GetSigningAlgorithm(key)) {
+ case PARCSigningAlgorithm_RSA:
+ switch (suite) {
+ case PARCCryptoSuite_RSA_SHA256:
+ return true;
+
+ case PARCCryptoSuite_RSA_SHA512:
+ return true;
+
+ default:
+ return false;
+ }
+ break;
+
+ case PARCSigningAlgorithm_ECDSA:
+ switch (suite) {
+ case PARCCryptoSuite_ECDSA_SHA256:
+ return true;
+
+ default:
+ return false;
+ }
+ break;
+
+
+ case PARCSigningAlgorithm_DSA:
+ switch (suite) {
+ default:
+ return false;
+ }
+ break;
+
+ case PARCSigningAlgorithm_HMAC:
+ switch (suite) {
+ case PARCCryptoSuite_HMAC_SHA256:
+ return true;
+ default:
+ return false;
+ }
+ break;
+
+ default:
+ trapUnexpectedState("Unknown signing algorithm: %s",
+ parcSigningAlgorithm_ToString(parcKey_GetSigningAlgorithm(key)));
+ return false;
+ }
+
+ return false;
+}
+
+static bool _parcInMemoryVerifier_RSAKey_Verify(PARCInMemoryVerifier *verifier, PARCCryptoHash *localHash,
+ PARCSignature *signatureToVerify, PARCBuffer *derEncodedKey);
+
+static bool _parcInMemoryVerifier_ECDSAKey_Verify(PARCInMemoryVerifier *verifier, PARCCryptoHash *localHash,
+ PARCSignature *signatureToVerify, PARCBuffer *derEncodedKey);
+/**
+ * The signature verifies if:
+ * 0) we know the key for keyid
+ * 1) the signing algorithm of the key corresponding to keyid is same as CCNxSignature
+ * 2) The hash of the locallyComputedHash is the same type as the content object's ciphersuite
+ * 3) the signature verifies
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static bool
+_parcInMemoryVerifier_VerifyDigest(void *interfaceContext, PARCKeyId *keyid, PARCCryptoHash *locallyComputedHash,
+ PARCCryptoSuite suite, PARCSignature *objectSignature)
+{
+ PARCInMemoryVerifier *verifier = (PARCInMemoryVerifier *) interfaceContext;
+
+ const PARCKey *key = parcCryptoCache_GetKey(verifier->key_cache, keyid);
+ if (key == NULL) {
+ return false;
+ }
+
+ assertTrue(_parcInMemoryVerifier_AllowedCryptoSuite(interfaceContext, keyid, suite), "Invalid crypto suite for keyid");
+
+ if (parcKey_GetSigningAlgorithm(key) != parcSignature_GetSigningAlgorithm(objectSignature)) {
+ fprintf(stdout, "Signatured failed, signing algorithms do not match: key %s sig %s\n",
+ parcSigningAlgorithm_ToString(parcKey_GetSigningAlgorithm(key)),
+ parcSigningAlgorithm_ToString(parcSignature_GetSigningAlgorithm(objectSignature)));
+ return false;
+ }
+
+ if (parcCryptoHash_GetDigestType(locallyComputedHash) != parcCryptoSuite_GetCryptoHash(suite)) {
+ fprintf(stdout, "Signatured failed, digest algorithms do not match: digest %s suite %s\n",
+ parcCryptoHashType_ToString(parcCryptoHash_GetDigestType(locallyComputedHash)),
+ parcCryptoHashType_ToString(parcCryptoSuite_GetCryptoHash(suite)));
+ return false;
+ }
+
+ switch (parcSignature_GetSigningAlgorithm(objectSignature)) {
+ case PARCSigningAlgorithm_RSA:
+ return _parcInMemoryVerifier_RSAKey_Verify(verifier, locallyComputedHash, objectSignature, parcKey_GetKey(key));
+
+ case PARCSigningAlgorithm_ECDSA:
+ return _parcInMemoryVerifier_ECDSAKey_Verify(verifier, locallyComputedHash, objectSignature, parcKey_GetKey(key));
+
+ case PARCSigningAlgorithm_DSA:
+ trapNotImplemented("DSA not supported");
+ break;
+
+ case PARCSigningAlgorithm_HMAC:
+ trapNotImplemented("HMAC not supported");
+ break;
+
+ default:
+ trapUnexpectedState("Unknown signing algorithm: %d", parcSignature_GetSigningAlgorithm(objectSignature));
+ }
+
+
+ return false;
+}
+
+static void
+_parcInMemoryVerifier_AddKey(void *interfaceContext, PARCKey *key)
+{
+ assertNotNull(interfaceContext, "interfaceContext must be non-null");
+ assertNotNull(key, "key must be non-null");
+
+ PARCInMemoryVerifier *verifier = (PARCInMemoryVerifier *) interfaceContext;
+ bool success = parcCryptoCache_AddKey(verifier->key_cache, key);
+ assertTrue(success, "could not add key, it must be a duplicate");
+}
+
+static void
+_parcInMemoryVerifier_RemoveKeyId(void *interfaceContext, PARCKeyId *keyid)
+{
+ assertNotNull(interfaceContext, "interfaceContent must be non-null");
+ assertNotNull(keyid, "key must be non-null");
+
+ PARCInMemoryVerifier *verifier = (PARCInMemoryVerifier *) interfaceContext;
+ parcCryptoCache_RemoveKey(verifier->key_cache, keyid);
+}
+
+// ==============================================================
+// Openssl specific parts
+
+#ifdef __APPLE__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+/**
+ * Return if the signature and key verify with the local hash.
+ *
+ * PRECONDITION:
+ * - You know the signature and key are RSA.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static bool
+_parcInMemoryVerifier_RSAKey_Verify(PARCInMemoryVerifier *verifier, PARCCryptoHash *localHash,
+ PARCSignature *signatureToVerify, PARCBuffer *derEncodedKey)
+{
+ const uint8_t *der_bytes = parcByteArray_Array(parcBuffer_Array(derEncodedKey));
+
+ long der_length = parcBuffer_Remaining(derEncodedKey);
+ EVP_PKEY *unwrapped_key = d2i_PUBKEY(NULL, &der_bytes, der_length);
+
+ if (unwrapped_key != NULL) {
+ int success = 0;
+ RSA *rsa = EVP_PKEY_get1_RSA(unwrapped_key);
+
+ if (rsa != NULL) {
+ int openssl_digest_type;
+
+ switch (parcCryptoHash_GetDigestType(localHash)) {
+ case PARCCryptoHashType_SHA256:
+ openssl_digest_type = NID_sha256;
+ break;
+ case PARCCryptoHashType_SHA512:
+ openssl_digest_type = NID_sha512;
+ break;
+ default:
+ trapUnexpectedState("Unknown digest type: %s",
+ parcCryptoHashType_ToString(parcCryptoHash_GetDigestType(localHash)));
+ }
+
+ PARCBuffer *sigbits = parcSignature_GetSignature(signatureToVerify);
+ PARCByteArray *bytearray = parcBuffer_Array(sigbits);
+ unsigned signatureLength = (unsigned) parcBuffer_Remaining(sigbits);
+ uint8_t *sigbuffer = parcByteArray_Array(bytearray);
+ size_t signatureOffset = parcBuffer_ArrayOffset(sigbits);
+
+ success = RSA_verify(openssl_digest_type,
+ (unsigned char *) parcByteArray_Array(parcBuffer_Array(parcCryptoHash_GetDigest(localHash))),
+ (unsigned) parcBuffer_Remaining(parcCryptoHash_GetDigest(localHash)),
+ sigbuffer + signatureOffset,
+ signatureLength,
+ rsa);
+ RSA_free(rsa);
+ }
+ EVP_PKEY_free(unwrapped_key);
+
+ if (success == 1) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Return if the signature and key verify with the local hash.
+ *
+ * PRECONDITION:
+ * - You know the signature and key are ECDSA.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static bool
+_parcInMemoryVerifier_ECDSAKey_Verify(PARCInMemoryVerifier *verifier, PARCCryptoHash *localHash,
+ PARCSignature *signatureToVerify, PARCBuffer *derEncodedKey)
+{
+ const uint8_t *der_bytes = parcByteArray_Array(parcBuffer_Array(derEncodedKey));
+
+ long der_length = parcBuffer_Remaining(derEncodedKey);
+ EVP_PKEY *unwrapped_key = d2i_PUBKEY(NULL, &der_bytes, der_length);
+
+ if (unwrapped_key != NULL) {
+ int success = 0;
+ EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(unwrapped_key);
+
+ if (ec_key != NULL) {
+ int openssl_digest_type;
+
+ switch (parcCryptoHash_GetDigestType(localHash)) {
+ case PARCCryptoHashType_SHA256:
+ openssl_digest_type = NID_sha256;
+ break;
+ case PARCCryptoHashType_SHA512:
+ openssl_digest_type = NID_sha512;
+ break;
+ default:
+ trapUnexpectedState("Unknown digest type: %s",
+ parcCryptoHashType_ToString(parcCryptoHash_GetDigestType(localHash)));
+ }
+
+ PARCBuffer *sigbits = parcSignature_GetSignature(signatureToVerify);
+ PARCByteArray *bytearray = parcBuffer_Array(sigbits);
+ unsigned signatureLength = (unsigned) parcBuffer_Remaining(sigbits);
+ uint8_t *sigbuffer = parcByteArray_Array(bytearray);
+ size_t signatureOffset = parcBuffer_Position(sigbits);
+
+ success = ECDSA_verify(openssl_digest_type,
+ (unsigned char *) parcByteArray_Array(parcBuffer_Array(parcCryptoHash_GetDigest(localHash))),
+ (unsigned) parcBuffer_Remaining(parcCryptoHash_GetDigest(localHash)),
+ sigbuffer + signatureOffset,
+ signatureLength,
+ ec_key);
+ EC_KEY_free(ec_key);
+ }
+ EVP_PKEY_free(unwrapped_key);
+
+ if (success == 1) {
+ return true;
+ }
+ }
+ return false;
+}
+
+PARCVerifierInterface *PARCInMemoryVerifierAsVerifier = &(PARCVerifierInterface) {
+ .GetCryptoHasher = _parcInMemoryVerifier_GetCryptoHasher,
+ .VerifyDigest = _parcInMemoryVerifier_VerifyDigest,
+ .AddKey = _parcInMemoryVerifier_AddKey,
+ .RemoveKeyId = _parcInMemoryVerifier_RemoveKeyId,
+ .AllowedCryptoSuite = _parcInMemoryVerifier_AllowedCryptoSuite,
+};
+
+#ifdef __APPLE__
+#pragma clang diagnostic pop
+#endif
diff --git a/libparc/parc/security/parc_InMemoryVerifier.h b/libparc/parc/security/parc_InMemoryVerifier.h
new file mode 100755
index 00000000..bbec8130
--- /dev/null
+++ b/libparc/parc/security/parc_InMemoryVerifier.h
@@ -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.
+ */
+
+/**
+ * @file parc_InMemoryVerifier.h
+ * @ingroup security
+ * @brief In memory verifier
+ *
+ */
+#ifndef libparc_parc_InMemoryVerifier_h
+#define libparc_parc_InMemoryVerifier_h
+
+#include <parc/security/parc_Verifier.h>
+
+struct parc_inmemory_verifier;
+typedef struct parc_inmemory_verifier PARCInMemoryVerifier;
+
+
+extern PARCVerifierInterface *PARCInMemoryVerifierAsVerifier;
+/**
+ * Create an empty verifier. It's destroyed via the PARCVerifierInterface->Destroy call.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCInMemoryVerifier *parcInMemoryVerifier_Create(void);
+
+/**
+ * Increase the number of references to the given `PARCInMemoryVerifier` instance.
+ *
+ * A new instance is not created,
+ * only that the given instance's reference count is incremented.
+ * Discard the acquired reference by invoking `parcInMemoryVerifier_Release()`.
+ *
+ * @param [in] signer A pointer to a `PARCInMemoryVerifier` instance.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a PARCInMemoryVerifier instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCInMemoryVerifier *verifier = parcInMemoryVerifier_Create();
+ * PARCInMemoryVerifier *handle = parcInMemoryVerifier_Acquire(signer);
+ * // use the handle instance as needed
+ * }
+ * @endcode
+ */
+PARCInMemoryVerifier *parcInMemoryVerifier_Acquire(const PARCInMemoryVerifier *verifier);
+
+/**
+ * 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.
+ *
+ * The contents of the dealloced memory used for the PARC object are undefined.
+ * Do not reference the object after the last release.
+ *
+ * @param [in,out] verifierPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCInMemoryVerifier *verifier = parcInMemoryVerifier_Create();
+ *
+ * parcInMemoryVerifier_Release(&verifier);
+ * }
+ * @endcode
+ */
+void parcInMemoryVerifier_Release(PARCInMemoryVerifier **verifierPtr);
+#endif // libparc_parc_InMemoryVerifier_h
diff --git a/libparc/parc/security/parc_Key.c b/libparc/parc/security/parc_Key.c
new file mode 100755
index 00000000..3802549e
--- /dev/null
+++ b/libparc/parc/security/parc_Key.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 <string.h>
+#include <stdio.h>
+
+#include <parc/security/parc_Key.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+#include <LongBow/runtime.h>
+
+struct parc_key {
+ PARCKeyId *keyid;
+ PARCSigningAlgorithm signingAlg;
+ PARCBuffer *key;
+};
+
+static void
+_parcKey_FinalRelease(PARCKey **keyP)
+{
+ if ((*keyP)->keyid != NULL) {
+ parcKeyId_Release(&(*keyP)->keyid);
+ }
+ if ((*keyP)->key != NULL) {
+ parcBuffer_Release(&(*keyP)->key);
+ }
+}
+
+parcObject_ExtendPARCObject(PARCKey, _parcKey_FinalRelease, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static PARCKey *
+_parcKey_Create()
+{
+ PARCKey *key = parcObject_CreateInstance(PARCKey);
+ return key;
+}
+
+/**
+ * Create a Key for use with the specified signing algorithm.
+ *
+ * This method support Public Key alogirhtms
+ *
+ * For Public Key algorithms, the buffer should be a DER encoded key.
+ */
+PARCKey *
+parcKey_CreateFromDerEncodedPublicKey(PARCKeyId *keyid, PARCSigningAlgorithm signingAlg, PARCBuffer *derEncodedKey)
+{
+ assertNotNull(keyid, "Parameter keyid must be non-null");
+ assertNotNull(derEncodedKey, "Parameter derEncodedKey must be non-null");
+
+ // Exclude the symmetric key algorithms
+ switch (signingAlg) {
+ case PARCSigningAlgorithm_RSA: // fallthrough
+ case PARCSigningAlgorithm_DSA:
+ case PARCSigningAlgorithm_ECDSA:
+ break;
+
+ default:
+ trapIllegalValueIf(true, "Unknown key algorithm or symmetric key algorithm: %s\n", parcSigningAlgorithm_ToString(signingAlg));
+ }
+
+ PARCKey *key = _parcKey_Create();
+ assertNotNull(key, "Unable to allocate memory for PARCKey");
+
+ key->key = parcBuffer_Acquire(derEncodedKey);
+ key->signingAlg = signingAlg;
+ key->keyid = parcKeyId_Acquire(keyid);
+ return key;
+}
+
+/**
+ * Create a Key for use with the specified signing algorithm.
+ *
+ * This method support HMAC with symmetric keys.
+ *
+ * The secretkey is a set of random bytes.
+ */
+PARCKey *
+parcKey_CreateFromSymmetricKey(PARCKeyId *keyid, PARCSigningAlgorithm signingAlg, PARCBuffer *secretkey)
+{
+ assertNotNull(keyid, "Parameter keyid must be non-null");
+ assertNotNull(secretkey, "Parameter derEncodedKey must be non-null");
+
+ // Exclude the symmetric key algorithms
+ switch (signingAlg) {
+ case PARCSigningAlgorithm_HMAC:
+ break;
+
+ default:
+ trapIllegalValueIf(true, "Unknown key algorithm or symmetric key algorithm: %s\n", parcSigningAlgorithm_ToString(signingAlg));
+ }
+
+ PARCKey *key = _parcKey_Create();
+ assertNotNull(key, "Unable to allocate memory for PARCKey");
+
+ key->key = parcBuffer_Acquire(secretkey);
+ key->signingAlg = signingAlg;
+ key->keyid = parcKeyId_Acquire(keyid);
+ return key;
+}
+
+/**
+ * Destroys the key, keyid, and key byte buffer
+ */
+
+parcObject_ImplementAcquire(parcKey, PARCKey);
+
+parcObject_ImplementRelease(parcKey, PARCKey);
+
+void
+parcKey_AssertValid(PARCKey *keyPtr)
+{
+ assertNotNull(keyPtr, "Parameter must be non-null double pointer");
+ assertNotNull(keyPtr->key, "Parameter key must not be null");
+ assertNotNull(keyPtr->keyid, "Parameter keyId must not be null");
+}
+
+PARCKeyId *
+parcKey_GetKeyId(const PARCKey *key)
+{
+ assertNotNull(key, "Parameter must be non-null");
+ return key->keyid;
+}
+
+PARCSigningAlgorithm
+parcKey_GetSigningAlgorithm(const PARCKey *key)
+{
+ assertNotNull(key, "Parameter must be non-null");
+ return key->signingAlg;
+}
+
+PARCBuffer *
+parcKey_GetKey(const PARCKey *key)
+{
+ assertNotNull(key, "Parameter must be non-null");
+ return key->key;
+}
+
+/**
+ * keyA equals keyB iff the KeyIds are equal, the SigningAlgs are equal, and the keys are equal.
+ * NULL equals NULL, but NULL does not equal any non-NULL
+ */
+bool
+parcKey_Equals(const PARCKey *keyA, const PARCKey *keyB)
+{
+ if (keyA == keyB) {
+ return true;
+ }
+
+ if (keyA == NULL || keyB == NULL) {
+ return false;
+ }
+
+ if (keyA->signingAlg == keyB->signingAlg) {
+ if (parcKeyId_Equals(keyA->keyid, keyB->keyid)) {
+ if (parcBuffer_Equals(keyA->key, keyB->key)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+PARCKey *
+parcKey_Copy(const PARCKey *original)
+{
+ PARCKey *newkey = _parcKey_Create();
+ assertNotNull(newkey, "Unable to allocate memory for a new key");
+ newkey->key = parcBuffer_Copy(original->key);
+ newkey->keyid = parcKeyId_Copy(original->keyid);
+ newkey->signingAlg = original->signingAlg;
+ return newkey;
+}
+
+char *
+parcKey_ToString(const PARCKey *key)
+{
+ char *string;
+ int failure = asprintf(&string, "PARCKey {.KeyID=\"%s\", .SigningAlgorithm=\"%s\" }",
+ parcKeyId_ToString(key->keyid),
+ parcSigningAlgorithm_ToString(key->signingAlg));
+ assertTrue(failure > -1, "Error asprintf");
+
+ char *result = parcMemory_StringDuplicate(string, strlen(string));
+ free(string);
+
+ return result;
+}
diff --git a/libparc/parc/security/parc_Key.h b/libparc/parc/security/parc_Key.h
new file mode 100755
index 00000000..426405bb
--- /dev/null
+++ b/libparc/parc/security/parc_Key.h
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Key.h
+ * @ingroup security
+ * @brief A `PARCKey` encapsulates a raw public (asymmetric) or private (symmetric) key.
+ *
+ * The PARC security library supports both public (asymmetric) digital signature and
+ * private (symmetric) MAC algorithms. A key is used in each such scheme for computing
+ * the signature or MAC. This type encapsulates both the raw key used in such schemes, but also
+ * a KeyId used to identify the key for hash-based data structures and the target signing/MAC
+ * scheme to which the key is applied.
+ *
+ */
+#include <parc/security/parc_KeyId.h>
+
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_SigningAlgorithm.h>
+
+#include <parc/algol/parc_Buffer.h>
+
+#ifndef libparc_parc_Key_h
+#define libparc_parc_Key_h
+
+struct parc_key;
+typedef struct parc_key PARCKey;
+
+/**
+ * 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 `parcKey_Release()`.
+ *
+ * @param [in] key A pointer to the original instance.
+ *
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCKey *key = parcKey_Acquire(keyInstance);
+ *
+ * parcKey_Release(&key);
+ * }
+ * @endcode
+ *
+ * @see parcKey_Release
+ */
+PARCKey *parcKey_Acquire(const PARCKey *key);
+
+/**
+ * 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] keyPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCKey *key = parcKey_Acquire(keyInstance);
+ *
+ * parcKey_Release(&key);
+ * }
+ * @endcode
+ */
+void parcKey_Release(PARCKey **keyPtr);
+
+/**
+ * Check that the `PARCKey` instance is valid. It should be non-null,
+ * and any referenced data should also be valid.
+ *
+ * @param [in] key A pointer to the instance to check.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCKey *key = parcKey_Acquire(keyInstance);
+ *
+ * parcKey_AssertValid(key);
+ * }
+ * @endcode
+ */
+void parcKey_AssertValid(PARCKey *key);
+
+/**
+ * Create a Key for use with the specified signing algorithm.
+ *
+ * This method supports Public Key algorithms. For such algorithms,
+ * the buffer should be a DER encoded key.
+ *
+ * @param [in] keyid A `PARCKeyId` instance for the new key
+ * @param [in] signingAlg The signing algorithm which is to be associated with this key
+ * @param [in] derEncodedKey The raw, DER-encoded key
+ *
+ * @return NULL An error occurred
+ * @return non-NULL A pointer to a new PARCKey instance that must be deallocated via `parcKey_Destory()`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *derEncodedKey = ....;
+ * PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, derEncodedKey);
+ * parcBuffer_Release(&derEncodedKey);
+ * parcKeyId_Destroy(&keyid);
+ * // do stuff with key
+ * parcKey_Release(&key);
+ * }
+ */
+PARCKey *parcKey_CreateFromDerEncodedPublicKey(PARCKeyId *keyid, PARCSigningAlgorithm signingAlg, PARCBuffer *derEncodedKey);
+
+/**
+ * Create a Key for use with the specified signing algorithm.
+ *
+ * This method support HMAC with symmetric keys.
+ *
+ * The secretkey is a set of random bytes.
+ *
+ * @param [in] keyid A pointer to a PARCKeyId instance.
+ * @param [in] signingAlg A PARCSigningAlgorithm value (only MAC-like algorithms allowed)
+ * @param [in] secretkey A pointer to a PARCBuffer instance containing the secret key.
+ *
+ * @return NULL An error occurred
+ * @return non-NULL A pointer to a new PARCKey instance that must be deallocated via `parcKey_Destory()`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *symmetricKey = ....;
+ * PARCKey *key = parcKey_CreateFromSymmetricKey(keyid, PARCSigningAlgorithm_HMAC, symmetricKey);
+ * parcBuffer_Release(&symmetricKey);
+ * parcKeyId_Destroy(&keyid);
+ * // do stuff with key
+ * parcKey_Release(&key);
+ * }
+ * @endcode
+ *
+ * @see parcKey_Destory
+ */
+PARCKey *parcKey_CreateFromSymmetricKey(PARCKeyId *keyid, PARCSigningAlgorithm signingAlg, PARCBuffer *secretkey);
+
+/**
+ * Create an independent, deep-copy of the given instance.
+ *
+ * A new instance is created as a complete,
+ * independent copy of the original such that `Equals(original, copy) == true`.
+ *
+ * @param [in] key A pointer to a `PARCKey` instance.
+ *
+ * @return NULL An error occurred
+ * @return non-NULL A pointer to a new PARCKey instance that must be deallocated via `parcKey_Release()`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *derEncodedKey = ....;
+ * PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, derEncodedKey);
+ * parcBuffer_Release(&derEncodedKey);
+ * parcKeyId_Destroy(&keyid);
+ * PARCKey *copy = parcKey_Copy(key);
+ * // do stuff with the key copy, which is equals to the original key instance
+ * parcKey_Release(&key);
+ * parcKey_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCKey *parcKey_Copy(const PARCKey *key);
+
+/**
+ * Determine if two `PARCKey` instances are equal.
+ * Two instances of PARCKey are equal iff the key digests are equal,
+ * the signing algorithms are equal, and the keys are equal.
+ *
+ * Two NULL keys are equal, but NULL does not equal any non-NULL
+ *
+ * The following equivalence relations on non-null `XXX` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `Equals(x, y)` must return true if and only if
+ * `Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `Equals(x, y)` returns true and
+ * `Equals(y, z)` returns true,
+ * then `Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `Equals(x, NULL)` must return false.
+ *
+ * @param [in] keyA A pointer to a `PARCKey` instance.
+ * @param [in] keyB A pointer to a `PARCKey` instance.
+ *
+ * @return true `PARCKey` keyA and keyB are equal.
+ * @return false `PARCKey` keyA and keyB are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCKey *keyA = parcKey_Create(...);
+ * PARCKey *keyB = parcKey_Create(...);
+ *
+ * if (parcBuffer_Equals(keyA, keyB)) {
+ * printf("Keys are equal.\n");
+ * } else {
+ * printf("Keys are NOT equal.\n");
+ * }
+ *
+ * parcKey_Release(&bufferA);
+ * parcKey_Release(&bufferB);
+ * }
+ * @endcode
+ */
+bool parcKey_Equals(const PARCKey *keyA, const PARCKey *keyB);
+
+/**
+ * Retrieve the `PARCKeyId` associated with the specified `PARCKey` instance.
+ *
+ * You must Aqcuire your own reference if you will store the key.
+ * Do not release this instance.
+ *
+ * @param [in] key A pointer to the `PARCKey` instance
+ *
+ * @return PARCKeyId A pointer to the `PARCKeyId` associated with this `PARCKey` instance. A handle is not acquired.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *derEncodedKey = ....;
+ * PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, derEncodedKey);
+ * parcBuffer_Release(&derEncodedKey);
+ * parcKeyId_Destroy(&keyid);
+ * PARCKeyId *innerKeyId = parcKey_GetKeyId(key);
+ * // use the innerKeyId as needed - DO NOT RELEASE IT via parcKeyId_Release()
+ * }
+ * @endcode
+ */
+PARCKeyId *parcKey_GetKeyId(const PARCKey *key);
+
+/**
+ * Retrieve the `PARCSigningAlgorithm` associated with the specified `PARCKey` instance.
+ *
+ * @param [in] key A pointer to the `PARCKey` instance
+ *
+ * @return PARCSigningAlgorithm A PARCSigningAlgorithm value
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *derEncodedKey = ....;
+ * PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, derEncodedKey);
+ * parcBuffer_Release(&derEncodedKey);
+ * parcKeyId_Destroy(&keyid);
+ * PARCSigningAlgorithm signingAlg = parcKey_GetSigningAlgorithm(key);
+ * // use the signingAlg value as needed
+ * }
+ * @endcode
+ */
+PARCSigningAlgorithm parcKey_GetSigningAlgorithm(const PARCKey *key);
+
+/**
+ * Returns the key's instance of the key buffer.
+ *
+ * You must Aqcuire your own reference if you will store the key.
+ * Do not release this instance.
+ *
+ * @param [in] key A pointer to the `PARCKey` instance
+ *
+ * @return PARCBuffer A pointer to the `PARCBuffer` associated with this `PARCKey` instance. A handle is not acquired.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *derEncodedKey = ....;
+ * PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, derEncodedKey);
+ * parcBuffer_Release(&derEncodedKey);
+ * parcKeyId_Destroy(&keyid);
+ * PARCBuffer *innerKey = parcKey_GetKey(key);
+ * // use the innerKey as needed - DO NOT RELEASE IT via parcBuffer_Release()
+ * }
+ * @endcode
+ */
+PARCBuffer *parcKey_GetKey(const PARCKey *key);
+
+/**
+ * Create a null-terminated string representation of the given `PARCKey`.
+ *
+ * The returned value must be freed by the caller using {@link parcMemory_Deallocate()}.
+ *
+ * @param [in] link A pointer to a `PARCKey` 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 *parcKey_ToString(const PARCKey *key);
+#endif // libparc_parc_Key_h
diff --git a/libparc/parc/security/parc_KeyId.c b/libparc/parc/security/parc_KeyId.c
new file mode 100755
index 00000000..1dbd9512
--- /dev/null
+++ b/libparc/parc/security/parc_KeyId.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 <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_KeyId.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Hash.h>
+
+struct parc_keyid {
+ PARCBuffer *keyid;
+ PARCHashCode hashcode;
+};
+
+static void
+_parcKeyId_Destroy(PARCKeyId **keyIdPtr)
+{
+ PARCKeyId *keyId = *keyIdPtr;
+
+ parcBuffer_Release(&keyId->keyid);
+}
+
+parcObject_ExtendPARCObject(PARCKeyId, _parcKeyId_Destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+void
+parcKeyId_AssertValid(const PARCKeyId *keyId)
+{
+ assertNotNull(keyId, "Pointer must be a non-null pointer to a PARCKeyId");
+}
+
+PARCKeyId *
+parcKeyId_Create(PARCBuffer *preComputedKeyId)
+{
+ PARCKeyId *keyid = parcObject_CreateInstance(PARCKeyId);
+
+ if (keyid != NULL) {
+ keyid->keyid = parcBuffer_Acquire(preComputedKeyId);
+ keyid->hashcode = parcBuffer_HashCode(preComputedKeyId);
+ }
+ return keyid;
+}
+
+parcObject_ImplementAcquire(parcKeyId, PARCKeyId);
+parcObject_ImplementRelease(parcKeyId, PARCKeyId);
+
+bool
+parcKeyId_Equals(const PARCKeyId *keyidA, const PARCKeyId *keyidB)
+{
+ if (keyidA == keyidB) {
+ return true;
+ }
+
+ if (keyidA == NULL || keyidB == NULL) {
+ return false;
+ }
+
+ return parcBuffer_Equals(keyidA->keyid, keyidB->keyid);
+}
+
+PARCHashCode
+parcKeyId_HashCode(const PARCKeyId *keyid)
+{
+ parcKeyId_OptionalAssertValid(keyid);
+
+ return keyid->hashcode;
+}
+
+PARCHashCode
+parcKeyId_HashCodeFromVoid(const void *keyid)
+{
+ parcKeyId_OptionalAssertValid(keyid);
+
+ return ((PARCKeyId *) keyid)->hashcode;
+}
+
+const PARCBuffer *
+parcKeyId_GetKeyId(const PARCKeyId *keyid)
+{
+ parcKeyId_OptionalAssertValid(keyid);
+
+ return keyid->keyid;
+}
+
+PARCKeyId *
+parcKeyId_Copy(const PARCKeyId *original)
+{
+ parcKeyId_OptionalAssertValid(original);
+
+ PARCBuffer *bufferCopy = parcBuffer_Copy(original->keyid);
+ PARCKeyId *result = parcKeyId_Create(bufferCopy);
+ parcBuffer_Release(&bufferCopy);
+ return result;
+}
+
+PARCBufferComposer *
+parcKeyId_BuildString(const PARCKeyId *keyid, PARCBufferComposer *composer)
+{
+ // output format = "0x<hex>\00"
+ parcBufferComposer_Format(composer, "0x");
+ for (int i = 0; i < parcBuffer_Capacity(keyid->keyid); i += 2) {
+ parcBufferComposer_Format(composer, "%02X", parcBuffer_GetAtIndex(keyid->keyid, i));
+ }
+ return composer;
+}
+
+char *
+parcKeyId_ToString(const PARCKeyId *keyid)
+{
+ char *result = NULL;
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ if (composer != NULL) {
+ parcKeyId_BuildString(keyid, composer);
+ PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+ result = parcBuffer_ToString(tempBuffer);
+ parcBuffer_Release(&tempBuffer);
+ parcBufferComposer_Release(&composer);
+ }
+ return result;
+}
diff --git a/libparc/parc/security/parc_KeyId.h b/libparc/parc/security/parc_KeyId.h
new file mode 100755
index 00000000..daa2a2fe
--- /dev/null
+++ b/libparc/parc/security/parc_KeyId.h
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_KeyId.h
+ * @ingroup security
+ * @brief Represent a key by an octet string
+ *
+ * A KeyId is a hash digest used to identify a key. These are used as key entries in hash-table
+ * based key stores that cache raw keys. Instead of transferring raw keys, parties may exchange
+ * KeyIds used to index into key stores for constant-time key retrieval. This exchange
+ * expects that the raw key will be present in the key store. If not, the lookup will fail.
+ * Consequently, KeyIds are not used to encapsulate or transfer raw keys.
+ *
+ */
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_BufferComposer.h>
+
+#ifndef libparc_parc_KeyId_h
+#define libparc_parc_KeyId_h
+
+struct parc_keyid;
+/**
+ * @typedef PARCKeyId
+ * @brief A KeyId is a hash digest used to identify a key.
+ */
+
+typedef struct parc_keyid PARCKeyId;
+
+/**
+ * @def parcKeyId_OptionalAssertValid
+ * Optional validation of the given instance.
+ *
+ * Define `PARCLibrary_DISABLE_VALIDATION` to disable validation.
+ */
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcKeyId_OptionalAssertValid(_instance_)
+#else
+# define parcKeyId_OptionalAssertValid(_instance_) parcKeyId_AssertValid(_instance_)
+#endif
+
+/**
+ * Create a `PARCKeyId` from the given pre-computed-key identifier.
+ *
+ * A reference to the given identifer is created and the caller is responsible for releasing the remaining references.
+ *
+ * @param [in] preComputedKeyId A pointer to a `PARCBuffer` instance containing the pre-computed-key identifier.
+ * @return A pointer to an allocated `PARCKeyId` that must be released via `parcKeyId_Release`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *keybits = parcBuffer_Wrap("Hello", 5, 0, 5);
+ * PARCKeyId *keyid = parcKeyId_Create(keybits);
+ * parcBuffer_Release(&keybits);
+ * // do something with keyid
+ * parcKeyId_Release(&keyid);
+ * }
+ * @endcode
+ */
+PARCKeyId *parcKeyId_Create(PARCBuffer *preComputedKeyId);
+
+/**
+ * Increase the number of references to a `PARCKeyId`.
+ *
+ * Note that new `PARCKeyId` is not created,
+ * only that the given `PARCKeyId` reference count is incremented.
+ * Discard the reference by invoking `parcKeyId_Release`.
+ *
+ * @param [in] instance A pointer to the instance of `PARCKeyId`.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap("Hello", 5, 0, 5);
+ * PARCKeyId *instance = parcKeyId_CreateFromByteBuffer(buffer);
+ * parcBuffer_Release(&buffer);
+ *
+ * PARCKeyId *reference = parcKeyId_Acquire(instance);
+ *
+ * parcKeyId_Release(&instance);
+ * parcKeyId_Release(&reference);
+ * }
+ * @endcode
+ *
+ * @see parcKeyId
+ */
+PARCKeyId *parcKeyId_Acquire(const PARCKeyId *instance);
+
+/**
+ * Assert a valid PARCKeyId instance.
+ *
+ * @param [in] keyId A pointer to a `PARCKeyId` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap("Hello", 5, 0, 5);
+ * PARCKeyId *instance = parcKeyId_CreateFromByteBuffer(buffer);
+ * parcBuffer_Release(&buffer);
+ *
+ * parcKeyId_AssertValid(&instance);
+ * parcKeyId_Release(&instance);
+ * }
+ * @endcode
+ * @see parcKeyId_OptionalAssertValid
+ */
+void parcKeyId_AssertValid(const PARCKeyId *keyId);
+
+/**
+ * Create a copy of the KeyId from the specified `PARCKeyId` instance.
+ *
+ * A deep copy is performed, acquiring handles to objects when needed.
+ *
+ * @param [in] original A pointer to a `PARCKeyId` instance containing the pre-computerd-key identifier.
+ * @return A pointer to a newly allocated `PARCKeyId` that must be released via `parcKeyId_Release`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *keybits = parcBuffer_Wrap("Hello", 5, 0, 5);
+ * PARCKeyId *keyid = parcKeyId_Create(keybits);
+ * parcBuffer_Release(&keybits);
+ * // do something with keyid
+ * parcKeyId_Release(&keyid);
+ * }
+ * @endcode
+ */
+PARCKeyId *parcKeyId_Copy(const PARCKeyId *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] object A pointer to a pointer to the `PARCKeyId` instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap("Hello", 5, 0, 5);
+ * PARCKeyId *instance = parcKeyId_CreateFromByteBuffer(buffer);
+ * parcBuffer_Release(&buffer);
+ *
+ * parcKeyId_Release(&instance);
+ * }
+ * @endcode
+ */
+void parcKeyId_Release(PARCKeyId **object);
+
+/**
+ * Determine if two `PARCKeyId` instances are equal.
+ *
+ * Two `PARCKeyId` instances are equal if, and only if,
+ *
+ * The following equivalence relations on non-null `PARCKeyId` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcKeyId_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcKeyId_Equals(x, y)` must return true if and only if
+ * `parcKeyId_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcKeyId_Equals(x, y)` returns true and
+ * `parcKeyId_Equals(y, z)` returns true,
+ * then `parcKeyId_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcKeyId_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcKeyId_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `PARCKeyId` instance.
+ * @param b A pointer to a `PARCKeyId` instance.
+ * @return true if the two `PARCKeyId` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCKeyId *a = parcKeyId_Create(...);
+ * PARCKeyId *b = parcKeyId_Create(...);
+ *
+ * if (parcKeyId_Equals(a, b)) {
+ * // equal
+ * } else {
+ * // unequal
+ * }
+ * }
+ * @endcode
+ */
+bool parcKeyId_Equals(const PARCKeyId *a, const PARCKeyId *b);
+
+/**
+ * Get the digest bytes of a `PARCKeyId` instance;
+ *
+ * @param [in] keyid A pointer to a `PARCKeyId` instance.
+ *
+ * @return A pointer to a (shared) {@link PARCBuffer} instance containing the digest bytes of the `PARCKeyId`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *buffer = parcBuffer_Wrap("Hello", 5, 0, 5);
+ * PARCKeyId *instance = parcKeyId_CreateFromByteBuffer(buffer);
+ * PARCBuffer *bytes = parcKeyId_GetKeyId(instance);
+ * // use or display the bytes buffer as needed
+ * }
+ * @endcode
+ */
+const PARCBuffer *parcKeyId_GetKeyId(const PARCKeyId *keyid);
+
+/**
+ * Returns a hash code value for the given instance.
+ *
+ * The general contract of `parcKeyId_HashCode` is:
+ *
+ * Whenever it is invoked on the same instance more than once during an
+ * execution of an application,
+ * the {@link parcKeyId_HashCode} function must consistently return the same value,
+ * provided no information used in a corresponding {@link parcKeyId_Equals}
+ * 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 parcKeyId_Equals} function,
+ * then calling the {@link parcKeyId_HashCode} function 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 parcKeyId_Equals} function,
+ * then calling the {@link parcKeyId_HashCode}
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] keyid A pointer to the `PARCKeyId` instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCKeyId *x = parcKeyId_Create(...);
+ * uint32_t hashValue = parcKeyId_HashCode(array);
+ * parcKeyId_Release(&x);
+ * }
+ * @endcode
+ */
+PARCHashCode parcKeyId_HashCode(const PARCKeyId *keyid);
+
+/**
+ * Compute a non-cryptographic hash of a `PARCKeyId` instance from a void pointer.
+ *
+ * This is useful for use in {@link PARCHashCodeTable}.
+ *
+ * @param [in] keyId A pointer to the instance to be hashed
+ *
+ * @return A 32-bit non-cryptographic hash of the instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCKeyId *x = parcKeyId_Create(...);
+ * uint32_t hash = parcKeyId_HashCode((void*)x);
+ * // use the hash to index into a table, or something else
+ * }
+ * @endcode
+ *
+ * @see parcKeyId_HashCode
+ */
+PARCHashCode parcKeyId_HashCodeFromVoid(const void *keyId);
+
+/**
+ * Append a representation of the specified instance to the given
+ * {@link PARCBufferComposer}.
+ *
+ * @param [in] keyId A pointer to a `PARCKeyId` instance.
+ * @param [in] composer A pointer to a `PARCBufferComposer` instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL The given `PARCBufferComposer`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBufferComposer *result = parcBufferComposer_Create();
+ *
+ * parcKeyId_BuildString(instance, result);
+ *
+ * char *string = parcBuffer_ToString(parcBufferComposer_ProduceBuffer(result));
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ *
+ * parcBufferComposer_Release(&result);
+ * }
+ * @endcode
+ */
+PARCBufferComposer *parcKeyId_BuildString(const PARCKeyId *keyId, 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] instance A pointer to the 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
+ * {
+ * PARCKeyId *instance = parcKeyId_Create(...);
+ *
+ * char *string = parcKeyId_ToString(instance);
+ *
+ * printf("Hello: %s\n", string);
+ * parcMemory_Deallocate((void **)&string);
+ *
+ * parcKeyId_Release(&instance);
+ * }
+ * @endcode
+ *
+ * @see parcKeyId_BuildString
+ */
+char *parcKeyId_ToString(const PARCKeyId *instance);
+#endif // libparc_parc_KeyId_h
diff --git a/libparc/parc/security/parc_KeyStore.c b/libparc/parc/security/parc_KeyStore.c
new file mode 100755
index 00000000..753fe118
--- /dev/null
+++ b/libparc/parc/security/parc_KeyStore.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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_KeyStore.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+struct parc_key_store {
+ PARCObject *instance;
+ const PARCKeyStoreInterface *interface;
+};
+
+static bool
+_parcKeyStore_Destructor(PARCKeyStore **keyStorePtr)
+{
+ PARCKeyStore *keyStore = *keyStorePtr;
+ if (keyStore->interface != NULL && keyStore->instance != NULL) {
+ parcObject_Release(&keyStore->instance);
+ }
+
+ return true;
+}
+
+parcObject_Override(PARCKeyStore, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcKeyStore_Destructor);
+
+parcObject_ImplementAcquire(parcKeyStore, PARCKeyStore);
+parcObject_ImplementRelease(parcKeyStore, PARCKeyStore);
+
+PARCKeyStore *
+parcKeyStore_Create(PARCObject *instance, const PARCKeyStoreInterface *interface)
+{
+ PARCKeyStore *keyStore = parcObject_CreateInstance(PARCKeyStore);
+
+ if (keyStore != NULL) {
+ keyStore->instance = parcObject_Acquire(instance);
+ keyStore->interface = interface;
+ }
+
+ return keyStore;
+}
+
+PARCCryptoHash *
+parcKeyStore_GetVerifierKeyDigest(const PARCKeyStore *interfaceContext)
+{
+ if (interfaceContext->interface != NULL) {
+ return interfaceContext->interface->getVerifierKeyDigest(interfaceContext->instance);
+ }
+ return NULL;
+}
+
+PARCCryptoHash *
+parcKeyStore_GetCertificateDigest(const PARCKeyStore *interfaceContext)
+{
+ if (interfaceContext->interface != NULL) {
+ return interfaceContext->interface->getCertificateDigest(interfaceContext->instance);
+ }
+ return NULL;
+}
+
+PARCBuffer *
+parcKeyStore_GetDEREncodedCertificate(const PARCKeyStore *interfaceContext)
+{
+ if (interfaceContext->interface != NULL) {
+ return interfaceContext->interface->getDEREncodedCertificate(interfaceContext->instance);
+ }
+ return NULL;
+}
+
+PARCBuffer *
+parcKeyStore_GetDEREncodedPublicKey(const PARCKeyStore *interfaceContext)
+{
+ if (interfaceContext->interface != NULL) {
+ return interfaceContext->interface->getDEREncodedPublicKey(interfaceContext->instance);
+ }
+ return NULL;
+}
+
+PARCBuffer *
+parcKeyStore_GetDEREncodedPrivateKey(const PARCKeyStore *interfaceContext)
+{
+ if (interfaceContext->interface != NULL) {
+ return interfaceContext->interface->getDEREncodedPrivateKey(interfaceContext->instance);
+ }
+ return NULL;
+}
+
+PARCSigningAlgorithm
+parcKeyStore_getSigningAlgorithm(const PARCKeyStore *interfaceContext)
+{
+ if (interfaceContext->interface != NULL) {
+ return interfaceContext->interface->getSigningAlgorithm(interfaceContext->instance);
+ }
+ return PARCSigningAlgorithm_NULL;
+}
diff --git a/libparc/parc/security/parc_KeyStore.h b/libparc/parc/security/parc_KeyStore.h
new file mode 100755
index 00000000..253505d5
--- /dev/null
+++ b/libparc/parc/security/parc_KeyStore.h
@@ -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.
+ */
+
+/**
+ * @file parc_KeyStore.h
+ * @ingroup security
+ * @brief A container of Key Store information.
+ *
+ * A Key Store is a repository of key information typically accessable
+ * through some authentication and authorisation system.
+ * The PARCKeyStore type contains the necessary information to successfully
+ * gain access to a Key Store.
+ *
+ */
+#ifndef libparc_parc_KeyStore_h
+#define libparc_parc_KeyStore_h
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/security/parc_CryptoHash.h>
+#include <parc/security/parc_SigningAlgorithm.h>
+
+struct parc_key_store;
+typedef struct parc_key_store PARCKeyStore;
+
+/**
+ * The hash of the signer's public key (or secret key for HMAC).
+ *
+ * Try using `parcSigner_CreateKeyId` for a sinterfaceer interface.
+ * You must destroy the returned PARCCryptoHash.
+ * For public key, its the SHA256 digest of the public key.
+ * For HMAC, its the SHA256 digest of the secret key.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der
+ * openssl sha256 -out test_rsa_pub_sha256.bin -sha256 -binary < test_rsa_pub.der
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A PARCCryptoHash value.
+ */
+typedef PARCCryptoHash *(PARCKeyStoreGetVerifierKeyDigest)(const void *interfaceContext);
+
+/**
+ * Returns a copy of the the certificate digest.
+ * Returns NULL for symmetric keystores.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ * openssl sha256 -out test_rsa_crt_sha256.bin -sha256 -binary < test_rsa_crt.der
+ * Which is also the same as (but not in der format)
+ * openssl x509 -in test_rsa.crt -fingerprint -sha256
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A `PARCCryptoHash` instance which internally contains a hash digest of the certificate used by the signer.
+ */
+typedef PARCCryptoHash *(PARCKeyStoreGetCertificateDigest)(const void *interfaceContext);
+
+/**
+ * Returns a copy of the DER encoded certificate.
+ * Returns NULL for symmetric keystores.
+ *
+ * Equivalent of:
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded certificate.
+ */
+typedef PARCBuffer *(PARCKeyStoreGetDEREncodedCertificate)(const void *interfaceContext);
+
+/**
+ * Returns a copy of the encoded public key in Distinguished Encoding Rules (DER) form.
+ *
+ * Equivalent of (for rsa/sha256):
+ * `openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der`
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded public key.
+ */
+typedef PARCBuffer *(PARCKeyStoreGetDEREncodedPublicKey)(const void *interfaceContext);
+
+/**
+ * Returns a copy of the encoded private key in Distinguished Encoding Rules (DER) form.
+ *
+ * Equivalent of (for rsa/sha256):
+ * `openssl rsa -in test_rsa_key.pem -outform DER -out test_rsa.der`
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded private key.
+ */
+typedef PARCBuffer *(PARCKeyStoreGetDEREncodedPrivateKey)(const void *interfaceContext);
+
+/**
+ * Returns the signing algorithm from the key type store in the keystore
+ *
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded private key.
+ */
+typedef PARCSigningAlgorithm (PARCKeyStoreGetSigningAlgorithm)(const void *interfaceContext);
+
+typedef struct parc_keystore_interface {
+ /**
+ * The hash of the signer's public key (or secret key for HMAC).
+ *
+ * Try using `parcSigner_CreateKeyId` for a sinterfaceer interface.
+ * You must destroy the returned PARCCryptoHash.
+ * For public key, its the SHA256 digest of the public key.
+ * For HMAC, its the SHA256 digest of the secret key.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der
+ * openssl sha256 -out test_rsa_pub_sha256.bin -sha256 -binary < test_rsa_pub.der
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A PARCCryptoHash value.
+ */
+ PARCKeyStoreGetVerifierKeyDigest *getVerifierKeyDigest;
+
+ /**
+ * Returns a copy of the the certificate digest.
+ * Returns NULL for symmetric keystores.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ * openssl sha256 -out test_rsa_crt_sha256.bin -sha256 -binary < test_rsa_crt.der
+ * Which is also the same as (but not in der format)
+ * openssl x509 -in test_rsa.crt -fingerprint -sha256
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A `PARCCryptoHash` instance which internally contains a hash digest of the certificate used by the signer.
+ */
+ PARCKeyStoreGetCertificateDigest *getCertificateDigest;
+
+ /**
+ * Returns a copy of the DER encoded certificate.
+ * Returns NULL for symmetric keystores.
+ *
+ * Equivalent of:
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded certificate.
+ */
+ PARCKeyStoreGetDEREncodedCertificate *getDEREncodedCertificate;
+
+ /**
+ * Returns a copy of the encoded public key in Distinguished Encoding Rules (DER) form.
+ *
+ * Equivalent of (for rsa/sha256):
+ * `openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der`
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded public key.
+ */
+ PARCKeyStoreGetDEREncodedPublicKey *getDEREncodedPublicKey;
+
+ /**
+ * Returns a copy of the encoded private key in Distinguished Encoding Rules (DER) form.
+ *
+ * Equivalent of (for rsa/sha256):
+ * `openssl rsa -in test_rsa_key.pem -outform DER -out test_rsa.der`
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded private key.
+ */
+ PARCKeyStoreGetDEREncodedPrivateKey *getDEREncodedPrivateKey;
+
+ /**
+ * Returns the signing algorithm from the key type store in the keystore
+ *
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded private key.
+ */
+ PARCKeyStoreGetSigningAlgorithm *getSigningAlgorithm;
+} PARCKeyStoreInterface;
+
+/**
+ * Create a `PARCKeyStore` from a filename.
+ *
+ * @param [in] instance A concrete instance of a `PARCKeyStore.`
+ * @param [in] interface The interface for the `PARCKeyStore.`
+ *
+ * @return A pointer to the new `PARCKeyStore`
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+PARCKeyStore *parcKeyStore_Create(PARCObject *instance, const PARCKeyStoreInterface *interface);
+
+/**
+ * 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 `parcKeyStore_Release()`.
+ *
+ * @param [in] keyStore A pointer to the original instance.
+ *
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCKeyStore *keyStore = parcKeyStore_Acquire(keyStoreInstance);
+ *
+ * parcKeyStore_Release(&keyStore);
+ * }
+ * @endcode
+ *
+ * @see parcKey_Release
+ */
+PARCKeyStore *parcKeyStore_Acquire(const PARCKeyStore *keyStore);
+
+/**
+ * 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] keyStorePtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCKeyStore *keyStore = parcKeyStore_Acquire(keyStoreInstance);
+ *
+ * parcKeyStore_Release(&keyStore);
+ * }
+ * @endcode
+ */
+void parcKeyStore_Release(PARCKeyStore **keyStorePtr);
+
+/**
+ * The hash of the signer's public key (or secret key for HMAC).
+ *
+ * Try using `parcSigner_CreateKeyId` for a sinterfaceer interface.
+ * You must destroy the returned PARCCryptoHash.
+ * For public key, its the SHA256 digest of the public key.
+ * For HMAC, its the SHA256 digest of the secret key.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der
+ * openssl sha256 -out test_rsa_pub_sha256.bin -sha256 -binary < test_rsa_pub.der
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A PARCCryptoHash value.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcKeyStore_GetVerifierKeyDigest(const PARCKeyStore *interfaceContext);
+
+/**
+ * Returns a copy of the the certificate digest.
+ * Returns NULL for symmetric keystores.
+ *
+ * Equivalent of (for rsa/sha256):
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ * openssl sha256 -out test_rsa_crt_sha256.bin -sha256 -binary < test_rsa_crt.der
+ * Which is also the same as (but not in der format)
+ * openssl x509 -in test_rsa.crt -fingerprint -sha256
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A `PARCCryptoHash` instance which internally contains a hash digest of the certificate used by the signer.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcKeyStore_GetCertificateDigest(const PARCKeyStore *interfaceContext);
+
+/**
+ * Returns a copy of the DER encoded certificate.
+ * Returns NULL for symmetric keystores.
+ *
+ * Equivalent of:
+ * openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded certificate.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+PARCBuffer *parcKeyStore_GetDEREncodedCertificate(const PARCKeyStore *interfaceContext);
+
+/**
+ * Returns a copy of the encoded public key in Distinguished Encoding Rules (DER) form.
+ *
+ * Equivalent of (for rsa/sha256):
+ * `openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der`
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded public key.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+PARCBuffer *parcKeyStore_GetDEREncodedPublicKey(const PARCKeyStore *interfaceContext);
+
+/**
+ * Returns a copy of the encoded private key in Distinguished Encoding Rules (DER) form.
+ *
+ * Equivalent of (for rsa/sha256):
+ * `openssl rsa -in test_rsa_key.pem -outform DER -out test_rsa.der`
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded private key.
+ *
+ * Example:
+ * @code
+ * {
+ * }
+ * @endcode
+ */
+PARCBuffer *parcKeyStore_GetDEREncodedPrivateKey(const PARCKeyStore *interfaceContext);
+
+/**
+ * Returns the signing algorithm from the key type store in the keystore
+ *
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCKeyStore instance.
+ *
+ * @return A pointer to a PARCBuffer containing the encoded private key.
+ */
+PARCSigningAlgorithm parcKeyStore_getSigningAlgorithm(const PARCKeyStore *interfaceContext);
+#endif // libparc_parc_KeyStore_h
diff --git a/libparc/parc/security/parc_KeyType.c b/libparc/parc/security/parc_KeyType.c
new file mode 100644
index 00000000..62fc0000
--- /dev/null
+++ b/libparc/parc/security/parc_KeyType.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_KeyType.h>
+
+static struct {
+ PARCKeyType type;
+ char *name;
+} _keyType_ToString[] = {
+ { PARCKeyType_RSA, "PARCKeyType_RSA" },
+ { PARCKeyType_EC, "PARCKeyType_EC" },
+ { 0, NULL }
+};
+
+const char *
+parcKeyType_ToString(PARCKeyType type)
+{
+ for (int i = 0; _keyType_ToString[i].name != NULL; i++) {
+ if (_keyType_ToString[i].type == type) {
+ return _keyType_ToString[i].name;
+ }
+ }
+ return NULL;
+}
+
+PARCKeyType
+parcKeyType_FromString(const char *name)
+{
+ for (int i = 0; _keyType_ToString[i].name != NULL; i++) {
+ if (strcmp(_keyType_ToString[i].name, name) == 0) {
+ return _keyType_ToString[i].type;
+ }
+ }
+ return PARCKeyType_Invalid;
+}
diff --git a/libparc/parc/security/parc_KeyType.h b/libparc/parc/security/parc_KeyType.h
new file mode 100644
index 00000000..92d58ed4
--- /dev/null
+++ b/libparc/parc/security/parc_KeyType.h
@@ -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.
+ */
+
+/**
+ * @file parc_KeyType.h
+ * @ingroup security
+ * @brief A type specifying a key.
+ *
+ */
+#ifndef libparc_parc_KeyType_h
+#define libparc_parc_KeyType_h
+
+typedef enum {
+ PARCKeyType_RSA,
+ PARCKeyType_EC,
+ PARCKeyType_Invalid
+} PARCKeyType;
+
+/**
+ * Convert the `PARCKeyType` value to a human-readable string representation.
+ *
+ * @param [in] type A `PARCKeyType` value
+ *
+ * @return A static, null-terminated string.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCKeyType type = PARCKeyType_RSA;
+ * const char *stringRep = parcKeyType_ToString(type);
+ * // use stringRep as necessary, and then free
+ * }
+ * @endcode
+ */
+const char *parcKeyType_ToString(PARCKeyType type);
+
+/**
+ * Convert a string representation value of a `PARCKeyType` to an actual value.
+ *
+ * @param [in] name A string representation of a `PARCKeyType` value.
+ *
+ * @return A `PARCKeyType` value.
+ *
+ * Example:
+ * @code
+ * {
+ * const char stringRep[17] = "PARCKeyType_RSA";
+ * PARCKeyType type = parcKeyType_FromString(stringRep);
+ * // use stringRep as necessary, and then free
+ * }
+ * @endcode
+ */
+PARCKeyType parcKeyType_FromString(const char *name);
+#endif // libparc_parc_KeyType_h
diff --git a/libparc/parc/security/parc_Pkcs12KeyStore.c b/libparc/parc/security/parc_Pkcs12KeyStore.c
new file mode 100644
index 00000000..c0d673c4
--- /dev/null
+++ b/libparc/parc/security/parc_Pkcs12KeyStore.c
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <LongBow/runtime.h>
+#include <LongBow/longBow_Compiler.h>
+
+#include <parc/algol/parc_Object.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_Signer.h>
+#include <parc/security/parc_KeyStore.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/security/parc_Certificate.h>
+#include <parc/security/parc_CertificateFactory.h>
+#include <parc/security/parc_CertificateType.h>
+#include <parc/security/parc_ContainerEncoding.h>
+#include <parc/security/parc_KeyType.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+
+#include <openssl/pkcs12.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+
+struct parc_pkcs12_keystore {
+ EVP_PKEY *private_key;
+ EVP_PKEY *public_key;
+ X509 *x509_cert;
+ PARCSigningAlgorithm signAlgo;
+
+ // These will be 0 length until asked for
+ PARCBuffer *public_key_digest;
+ PARCBuffer *certificate_digest;
+ PARCBuffer *public_key_der;
+ PARCBuffer *certificate_der;
+ PARCBuffer *private_key_der;
+
+ PARCCryptoHashType hashType;
+ PARCCryptoHasher *hasher;
+};
+
+static bool
+_parcPkcs12KeyStore_Finalize(PARCPkcs12KeyStore **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCPkcs12KeyStore pointer.");
+ PARCPkcs12KeyStore *keystore = *instancePtr;
+
+ EVP_PKEY_free(keystore->private_key);
+ EVP_PKEY_free(keystore->public_key);
+ X509_free(keystore->x509_cert);
+
+ if (keystore->public_key_digest != NULL) {
+ parcBuffer_Release(&keystore->public_key_digest);
+ }
+ if (keystore->certificate_digest != NULL) {
+ parcBuffer_Release(&keystore->certificate_digest);
+ }
+ if (keystore->public_key_der != NULL) {
+ parcBuffer_Release(&keystore->public_key_der);
+ }
+ if (keystore->certificate_der != NULL) {
+ parcBuffer_Release(&keystore->certificate_der);
+ }
+ if (keystore->private_key_der != NULL) {
+ parcBuffer_Release(&keystore->private_key_der);
+ }
+
+ parcCryptoHasher_Release(&(keystore->hasher));
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcPkcs12KeyStore, PARCPkcs12KeyStore);
+parcObject_ImplementRelease(parcPkcs12KeyStore, PARCPkcs12KeyStore);
+parcObject_Override(PARCPkcs12KeyStore, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcPkcs12KeyStore_Finalize);
+
+static int
+_parcPkcs12KeyStore_ParseFile(PARCPkcs12KeyStore *keystore, const char *filename, const char *password)
+{
+ parcSecurity_AssertIsInitialized();
+
+ FILE *fp = fopen(filename, "rb");
+
+ assertNotNull(fp, "Error opening %s: %s", filename, strerror(errno));
+ if (fp == NULL) {
+ return -1;
+ }
+
+ PKCS12 *p12Keystore = NULL;
+ d2i_PKCS12_fp(fp, &p12Keystore);
+ fclose(fp);
+
+ int success = PKCS12_parse(p12Keystore, password, &keystore->private_key, &keystore->x509_cert, NULL);
+ PKCS12_free(p12Keystore);
+
+ if (!success) {
+ unsigned long errcode;
+ while ((errcode = ERR_get_error()) != 0) {
+ fprintf(stderr, "openssl error: %s\n", ERR_error_string(errcode, NULL));
+ }
+ return -1;
+ }
+
+ keystore->public_key = X509_get_pubkey(keystore->x509_cert);
+ if (keystore->public_key) {
+#if OPENSSL_VERSION_NUMBER >= 0X10100000L
+ switch (EVP_PKEY_id(keystore->public_key)) {
+#else
+ switch (keystore->public_key->type) {
+#endif
+ case EVP_PKEY_RSA:
+ keystore->signAlgo = PARCSigningAlgorithm_RSA;
+ break;
+ case EVP_PKEY_DSA:
+ keystore->signAlgo = PARCSigningAlgorithm_DSA;
+ break;
+ case EVP_PKEY_EC:
+ keystore->signAlgo = PARCSigningAlgorithm_ECDSA;
+ break;
+ default:
+ fprintf(stderr, "%d bit unknown Key type\n\n", EVP_PKEY_bits(keystore->public_key));
+ break;
+ }
+ }
+ return 0;
+}
+
+// =============================================================
+LONGBOW_STOP_DEPRECATED_WARNINGS
+// =============================================================
+
+PKCS12 *_createPkcs12KeyStore_RSA(
+ PARCBuffer *privateKeyBuffer,
+ PARCCertificate *certificate,
+ const char *password)
+{
+ // Extract the private key
+ EVP_PKEY *privateKey = NULL;
+ uint8_t *privateKeyBytes = parcBuffer_Overlay(privateKeyBuffer, parcBuffer_Limit(privateKeyBuffer));
+ d2i_PrivateKey(EVP_PKEY_RSA, &privateKey, (const unsigned char **) &privateKeyBytes, parcBuffer_Limit(privateKeyBuffer));
+ parcBuffer_Release(&privateKeyBuffer);
+
+ // Extract the certificate
+ PARCBuffer *certBuffer = parcCertificate_GetDEREncodedCertificate(certificate);
+ uint8_t *certBytes = parcBuffer_Overlay(certBuffer, parcBuffer_Limit(certBuffer));
+ X509 *cert = NULL;
+ d2i_X509(&cert, (const unsigned char **) &certBytes, parcBuffer_Limit(certBuffer));
+
+ parcCertificate_Release(&certificate);
+
+ PKCS12 *pkcs12 = PKCS12_create((char *) password,
+ "ccnxuser",
+ privateKey,
+ cert,
+ NULL,
+ 0,
+ 0,
+ 0 /*default iter*/,
+ PKCS12_DEFAULT_ITER /*mac_iter*/,
+ 0);
+ X509_free(cert);
+ EVP_PKEY_free(privateKey);
+ return pkcs12;
+}
+
+PKCS12 *_createPkcs12KeyStore_ECDSA(
+ PARCBuffer *privateKeyBuffer,
+ PARCCertificate *certificate,
+ const char *password)
+{
+ // Extract the private key
+ EVP_PKEY *privateKey = NULL;
+ uint8_t *privateKeyBytes = parcBuffer_Overlay(privateKeyBuffer, parcBuffer_Limit(privateKeyBuffer));
+ d2i_PrivateKey(EVP_PKEY_EC, &privateKey, (const unsigned char **) &privateKeyBytes, parcBuffer_Limit(privateKeyBuffer));
+ parcBuffer_Release(&privateKeyBuffer);
+
+ // Extract the certificate
+ PARCBuffer *certBuffer = parcCertificate_GetDEREncodedCertificate(certificate);
+ uint8_t *certBytes = parcBuffer_Overlay(certBuffer, parcBuffer_Limit(certBuffer));
+ X509 *cert = NULL;
+ d2i_X509(&cert, (const unsigned char **) &certBytes, parcBuffer_Limit(certBuffer));
+
+ parcCertificate_Release(&certificate);
+
+ PKCS12 *pkcs12 = PKCS12_create((char *) password,
+ "ccnxuser",
+ privateKey,
+ cert,
+ NULL,
+ 0,
+ 0,
+ 0 /*default iter*/,
+ PKCS12_DEFAULT_ITER /*mac_iter*/,
+ 0);
+ X509_free(cert);
+ EVP_PKEY_free(privateKey);
+ return pkcs12;
+}
+
+bool
+parcPkcs12KeyStore_CreateFile(
+ const char *filename,
+ const char *password,
+ const char *subjectName,
+ PARCSigningAlgorithm signAlgo,
+ unsigned keyLength,
+ unsigned validityDays)
+{
+ parcSecurity_AssertIsInitialized();
+
+ bool result = false;
+
+ PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_DER);
+
+ PARCBuffer *privateKeyBuffer;
+ PARCCertificate *certificate = parcCertificateFactory_CreateSelfSignedCertificate(factory, &privateKeyBuffer, (char *) subjectName,signAlgo, keyLength, validityDays);
+
+ parcCertificateFactory_Release(&factory);
+
+ if (certificate != NULL) {
+
+ PKCS12 *pkcs12;
+ switch (signAlgo){
+ case PARCSigningAlgorithm_RSA:
+ pkcs12 = _createPkcs12KeyStore_RSA(privateKeyBuffer, certificate, password);
+ break;
+ case PARCSigningAlgorithm_ECDSA:
+ pkcs12 = _createPkcs12KeyStore_ECDSA(privateKeyBuffer, certificate, password);
+ break;
+ default:
+ return result;
+ }
+
+ if (pkcs12 != NULL) {
+ int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0600);
+ if (fd != -1) {
+ FILE *fp = fdopen(fd, "wb");
+ if (fp != NULL) {
+ i2d_PKCS12_fp(fp, pkcs12);
+ fclose(fp);
+ result = true;
+ } else {
+ trapUnrecoverableState("Cannot fdopen(3) the file descriptor %d", fd);
+ }
+ close(fd);
+ } else {
+ trapUnrecoverableState("Cannot open(2) the file '%s': %s", filename, strerror(errno));
+ }
+ PKCS12_free(pkcs12);
+ } else {
+ unsigned long errcode;
+ while ((errcode = ERR_get_error()) != 0) {
+ fprintf(stderr, "openssl error: %s\n", ERR_error_string(errcode, NULL));
+ }
+ trapUnrecoverableState("PKCS12_create returned a NULL value.");
+ }
+ }
+
+ return result;
+}
+
+PARCPkcs12KeyStore *
+parcPkcs12KeyStore_Open(const char *filename, const char *password, PARCCryptoHashType hashType)
+{
+ PARCPkcs12KeyStore *keyStore = parcObject_CreateAndClearInstance(PARCPkcs12KeyStore);
+ if (keyStore != NULL) {
+ keyStore->hasher = parcCryptoHasher_Create(hashType);
+ keyStore->public_key_digest = NULL;
+ keyStore->certificate_digest = NULL;
+ keyStore->public_key_der = NULL;
+ keyStore->certificate_der = NULL;
+ keyStore->hashType = hashType;
+
+ if (_parcPkcs12KeyStore_ParseFile(keyStore, filename, password) != 0) {
+ parcPkcs12KeyStore_Release(&keyStore);
+ }
+ }
+
+ return keyStore;
+}
+
+PARCSigningAlgorithm _GetSigningAlgorithm(PARCPkcs12KeyStore *keystore)
+{
+ return keystore->signAlgo;
+}
+
+static PARCCryptoHash *
+_GetPublickKeyDigest(PARCPkcs12KeyStore *keystore)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(keystore, "Parameter must be non-null PARCPkcs12KeyStore");
+
+#if 0
+ if (keystore->public_key_digest == NULL) {
+ AUTHORITY_KEYID *akid = X509_get_ext_d2i(keystore->x509_cert, NID_authority_key_identifier, NULL, NULL);
+ if (akid != NULL) {
+ ASN1_OCTET_STRING *skid = X509_get_ext_d2i(keystore->x509_cert, NID_subject_key_identifier, NULL, NULL);
+ if (skid != NULL) {
+ keystore->public_key_digest =
+ parcBuffer_PutArray(parcBuffer_Allocate(skid->length), skid->length, skid->data);
+ parcBuffer_Flip(keystore->public_key_digest);
+ ASN1_OCTET_STRING_free(skid);
+ }
+ AUTHORITY_KEYID_free(akid);
+ }
+ }
+#endif
+
+ // If we could not load the digest from the certificate, then calculate it from the public key.
+ if (keystore->public_key_digest == NULL) {
+ uint8_t digestBuffer[SHA256_DIGEST_LENGTH];
+
+ int result = ASN1_item_digest(ASN1_ITEM_rptr(X509_PUBKEY),
+ EVP_sha256(),
+ X509_get_X509_PUBKEY(keystore->x509_cert),
+ digestBuffer,
+ NULL);
+ if (result != 1) {
+ assertTrue(0, "Could not compute digest over certificate public key");
+ } else {
+ keystore->public_key_digest =
+ parcBuffer_PutArray(parcBuffer_Allocate(SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH, digestBuffer);
+ parcBuffer_Flip(keystore->public_key_digest);
+ }
+ }
+
+ // This stores a reference, so keystore->public_key_digest will remain valid
+ // even if the cryptoHasher is destroyed
+ return parcCryptoHash_Create(PARCCryptoHashType_SHA256, keystore->public_key_digest);
+}
+
+static PARCCryptoHash *
+_GetCertificateDigest(PARCPkcs12KeyStore *keystore)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(keystore, "Parameter must be non-null PARCPkcs12KeyStore");
+
+ if (keystore->certificate_digest == NULL) {
+ uint8_t digestBuffer[SHA256_DIGEST_LENGTH];
+ int result = X509_digest(keystore->x509_cert, EVP_sha256(), digestBuffer, NULL);
+ if (result) {
+ keystore->certificate_digest =
+ parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH, digestBuffer));
+ }
+ }
+
+ PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, keystore->certificate_digest);
+ return hash;
+}
+
+static PARCBuffer *
+_GetDEREncodedCertificate(PARCPkcs12KeyStore *keystore)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(keystore, "Parameter must be non-null PARCPkcs12KeyStore");
+
+ if (keystore->certificate_der == NULL) {
+ uint8_t *der = NULL;
+
+ // this allocates memory for der
+ int derLength = i2d_X509(keystore->x509_cert, &der);
+ if (derLength > 0) {
+ keystore->certificate_der =
+ parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(derLength), derLength, der));
+ }
+ OPENSSL_free(der);
+ }
+
+ return parcBuffer_Copy(keystore->certificate_der);
+}
+
+static PARCBuffer *
+_GetDEREncodedPublicKey(PARCPkcs12KeyStore *keystore)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(keystore, "Parameter must be non-null PARCPkcs12KeyStore");
+
+ if (keystore->public_key_der == NULL) {
+ uint8_t *der = NULL;
+
+ // this allocates memory for der
+ int derLength = i2d_PUBKEY(keystore->public_key, &der);
+ if (derLength > 0) {
+ keystore->public_key_der =
+ parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(derLength), derLength, der));
+ }
+ OPENSSL_free(der);
+ }
+
+ return parcBuffer_Copy(keystore->public_key_der);
+}
+
+static PARCBuffer *
+_GetDEREncodedPrivateKey(PARCPkcs12KeyStore *keystore)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(keystore, "Parameter must be non-null PARCPkcs12KeyStore");
+
+ if (keystore->private_key_der == NULL) {
+ uint8_t *der = NULL;
+
+ // this allocates memory for der
+ int derLength = i2d_PrivateKey(keystore->private_key, &der);
+ if (derLength > 0) {
+ keystore->private_key_der =
+ parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(derLength), derLength, der));
+ }
+ OPENSSL_free(der);
+ }
+
+ return parcBuffer_Copy(keystore->private_key_der);
+}
+
+PARCKeyStoreInterface *PARCPkcs12KeyStoreAsKeyStore = &(PARCKeyStoreInterface) {
+ .getVerifierKeyDigest = (PARCKeyStoreGetVerifierKeyDigest *) _GetPublickKeyDigest,
+ .getCertificateDigest = (PARCKeyStoreGetCertificateDigest *) _GetCertificateDigest,
+ .getDEREncodedCertificate = (PARCKeyStoreGetDEREncodedCertificate *) _GetDEREncodedCertificate,
+ .getDEREncodedPublicKey = (PARCKeyStoreGetDEREncodedPublicKey *) _GetDEREncodedPublicKey,
+ .getDEREncodedPrivateKey = (PARCKeyStoreGetDEREncodedPrivateKey *) _GetDEREncodedPrivateKey,
+ .getSigningAlgorithm = (PARCKeyStoreGetSigningAlgorithm *) _GetSigningAlgorithm,
+};
+
+// =============================================================
+LONGBOW_START_DEPRECATED_WARNINGS
+// =============================================================
diff --git a/libparc/parc/security/parc_Pkcs12KeyStore.h b/libparc/parc/security/parc_Pkcs12KeyStore.h
new file mode 100644
index 00000000..950284ea
--- /dev/null
+++ b/libparc/parc/security/parc_Pkcs12KeyStore.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Pkcs12KeyStore.h
+ * @ingroup security
+ * @brief A concrete implementation of PARCKeyStore based on a PCKS12 keystore.
+ *
+ */
+#ifndef libparc_parc_Pkcs12KeyStore_h
+#define libparc_parc_Pkcs12KeyStore_h
+
+#include <parc/security/parc_KeyStore.h>
+#include <parc/security/parc_Signer.h>
+#include <parc/security/parc_SigningAlgorithm.h>
+
+struct parc_pkcs12_keystore;
+typedef struct parc_pkcs12_keystore PARCPkcs12KeyStore;
+
+extern PARCKeyStoreInterface *PARCPkcs12KeyStoreAsKeyStore;
+
+/**
+ * Increase the number of references to a `PARCPkcs12KeyStore` instance.
+ *
+ * Note that new `PARCPkcs12KeyStore` is not created,
+ * only that the given `PARCPkcs12KeyStore` reference count is incremented.
+ * Discard the reference by invoking `parcPkcs12KeyStore_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCPkcs12KeyStore instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * parcPkcs12KeyStore_CreateFile(...);
+ * PARCPkcs12KeyStore *a = parcPkcs12Store_Open(...)
+ *
+ * PARCPkcs12KeyStore *b = parcPkcs12KeyStore_Acquire();
+ *
+ * parcPkcs12KeyStore_Release(&a);
+ * parcPkcs12KeyStore_Release(&b);
+ * }
+ * @endcode
+ */
+PARCPkcs12KeyStore *parcPkcs12KeyStore_Acquire(const PARCPkcs12KeyStore *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCPkcs12KeyStore` 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
+ * {
+ * PARCPkcs12KeyStore *a = parcPkcs12Store_Open(...);
+ *
+ * parcPkcs12KeyStore_Release(&a);
+ * }
+ * @endcode
+ */
+void parcPkcs12KeyStore_Release(PARCPkcs12KeyStore **instancePtr);
+
+/**
+ * Creates a PKCS12 keystore identity with a self-signed certifiate. Note that this call currently
+ * aborts if keystore i/o access fails, behavior that may change in the future.
+ *
+ * @param [in] filename The name of the PKCS12 file.
+ * @param [in] password The password to open the PKCS12 file.
+ * @param [in] subjectName The certificate subject associated with the PKCS12 file.
+ * @param [in] keyLength The length of the public key associated with the PKCS12 file.
+ * @param [in] validityDays The validity (in days) of the certificate associated with the PKCS12 file.
+ *
+ * @return true on success, false if certificate creation fails, and will abort if keystore i/o fails.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *filename = "/tmp/ccnxFileKeyStore_Pkcs12Open_CreateAndOpen.p12";
+ * const char *password = "12345";
+ * const char *subject = "alice";
+ * bool result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_RSA, 1024, 32);
+ * }
+ * @endcode
+ */
+bool parcPkcs12KeyStore_CreateFile(const char *filename, const char *password, const char *subjectName,
+ PARCSigningAlgorithm signAlgo, unsigned keyLength, unsigned validityDays);
+
+/**
+ * Create a `PARCPkcs12KeyStore` instance.
+ *
+ * @param [in] filename The name of a file containing the PKCS12 keystore.
+ * @param [in] password The password to decrypt/unlock the determines how the signer digests data. Supports PARCCryptoHashType_SHA256 and PARCCryptoHashType_SHA512.
+ * @param [in] hashType Determines how the signer digests data. Possible values are PARCCryptoHashType_SHA256 and PARCCryptoHashType_SHA512.
+ *
+ * @return A `PARCPkcs12KeyStore` instance using the public/private key pair contained within the PKCS12 file.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *filename = "/tmp/ccnxFileKeyStore_Pkcs12Open_CreateAndOpen.p12";
+ * const char *password = "12345";
+ * const char *subject = "alice";
+ * bool result = parcPkcs12KeyStore_CreateFile(filename, password, subject, 1024, 32);
+ *
+ * ...
+ *
+ * PARCSigningInterface *interface = parcPkcs12Store_Open(filename, password, PARCCryptoHashType_SHA256);
+ *
+ * ...
+ * }
+ * @endcode
+ */
+PARCPkcs12KeyStore *parcPkcs12KeyStore_Open(const char *filename, const char *password, PARCCryptoHashType hashType);
+#endif // libparc_parc_Pkcs12Store_h
diff --git a/libparc/parc/security/parc_PublicKeySigner.c b/libparc/parc/security/parc_PublicKeySigner.c
new file mode 100644
index 00000000..3c70a139
--- /dev/null
+++ b/libparc/parc/security/parc_PublicKeySigner.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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_Memory.h>
+
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_CryptoHash.h>
+#include <parc/security/parc_CryptoSuite.h>
+#include <parc/security/parc_Security.h>
+
+#include <openssl/pkcs12.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+
+struct PARCPublicKeySigner {
+ PARCKeyStore *keyStore;
+ PARCSigningAlgorithm signingAlgorithm;
+ PARCCryptoHashType hashType;
+ PARCCryptoHasher *hasher;
+};
+
+static bool
+_parcPublicKeySigner_Finalize(PARCPublicKeySigner **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCPublicKeySigner pointer.");
+
+ PARCPublicKeySigner *instance = *instancePtr;
+
+ if (instance->keyStore != NULL) {
+ parcKeyStore_Release(&(instance->keyStore));
+ }
+ if (instance->hasher != NULL) {
+ parcCryptoHasher_Release(&(instance->hasher));
+ }
+
+ return true;
+}
+
+void
+parcPublicKeySigner_AssertValid(const PARCPublicKeySigner *instance)
+{
+ assertTrue(parcPublicKeySigner_IsValid(instance), "PARCPublicKeySigner is not valid.");
+}
+
+bool
+parcPublicKeySigner_Equals(const PARCPublicKeySigner *x, const PARCPublicKeySigner *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (x->signingAlgorithm == y->signingAlgorithm) {
+ if (x->hashType == y->hashType) {
+ return true;
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcPublicKeySigner_HashCode(const PARCPublicKeySigner *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+parcPublicKeySigner_IsValid(const PARCPublicKeySigner *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+char *
+parcPublicKeySigner_ToString(const PARCPublicKeySigner *instance)
+{
+ char *result = parcMemory_Format("PARCPublicKeySigner@%p\n", instance);
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcPublicKeySigner, PARCPublicKeySigner);
+parcObject_ImplementRelease(parcPublicKeySigner, PARCPublicKeySigner);
+
+parcObject_Override(PARCPublicKeySigner, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcPublicKeySigner_Finalize,
+ .toString = (PARCObjectToString *) parcPublicKeySigner_ToString,
+ .equals = (PARCObjectEquals *) parcPublicKeySigner_Equals,
+ .hashCode = (PARCObjectHashCode *) parcPublicKeySigner_HashCode);
+
+PARCPublicKeySigner *
+parcPublicKeySigner_Create(PARCKeyStore *keyStore, PARCCryptoSuite suite)
+{
+ PARCPublicKeySigner *result = parcObject_CreateInstance(PARCPublicKeySigner);
+
+ PARCSigningAlgorithm signAlgo = parcCryptoSuite_GetSigningAlgorithm(suite);
+ PARCCryptoHashType hashType = parcCryptoSuite_GetCryptoHash(suite);
+
+
+ if (result != NULL) {
+ result->keyStore = parcKeyStore_Acquire(keyStore);
+ result->signingAlgorithm = signAlgo;
+ result->hashType = hashType;
+ result->hasher = parcCryptoHasher_Create(hashType);
+ }
+
+ return result;
+}
+
+static PARCSigningAlgorithm
+_GetSigningAlgorithm(PARCPublicKeySigner *signer)
+{
+ assertNotNull(signer, "Parameter must be non-null PARCCryptoHasher");
+ return signer->signingAlgorithm;
+}
+
+static PARCCryptoHashType
+_GetCryptoHashType(PARCPublicKeySigner *signer)
+{
+ assertNotNull(signer, "Parameter must be non-null PARCCryptoHasher");
+ return signer->hashType;
+}
+
+static PARCCryptoHasher *
+_GetCryptoHasher(PARCPublicKeySigner *signer)
+{
+ assertNotNull(signer, "Parameter must be non-null PARCCryptoHasher");
+ return signer->hasher;
+}
+
+static PARCKeyStore *
+_GetKeyStore(PARCPublicKeySigner *signer)
+{
+ assertNotNull(signer, "Parameter must be non-null PARCCryptoHasher");
+ return signer->keyStore;
+}
+
+static inline int _SignDigestRSA(const PARCCryptoHash *digestToSign, PARCBuffer *privateKeyBuffer, int opensslDigestType, uint8_t ** sig, unsigned * sigLength)
+{
+ EVP_PKEY *privateKey = NULL;
+ size_t keySize = parcBuffer_Remaining(privateKeyBuffer);
+ uint8_t *bytes = parcBuffer_Overlay(privateKeyBuffer, keySize);
+ privateKey = d2i_PrivateKey(EVP_PKEY_RSA, &privateKey, (const unsigned char **) &bytes, keySize);
+
+ RSA *rsa = EVP_PKEY_get1_RSA(privateKey);
+ *sig = parcMemory_Allocate(RSA_size(rsa));
+
+ assertNotNull(*sig, "parcMemory_Allocate(%u) returned NULL", RSA_size(rsa));
+
+ *sigLength = 0;
+ PARCBuffer *bb_digest = parcCryptoHash_GetDigest(digestToSign);
+ int result = RSA_sign(opensslDigestType,
+ (unsigned char *) parcByteArray_Array(parcBuffer_Array(bb_digest)),
+ (int) parcBuffer_Remaining(bb_digest),
+ *sig,
+ sigLength,
+ rsa);
+ assertTrue(result == 1, "Got error from RSA_sign: %d", result);
+ EVP_PKEY_free(privateKey);
+ RSA_free(rsa);
+ return result;
+}
+
+static inline int _SignDigestECDSA(const PARCCryptoHash *digestToSign, PARCBuffer *privateKeyBuffer, int opensslDigestType, uint8_t ** sig, unsigned * sigLength)
+{
+ EVP_PKEY *privateKey = NULL;
+ size_t keySize = parcBuffer_Remaining(privateKeyBuffer);
+ uint8_t *bytes = parcBuffer_Overlay(privateKeyBuffer, keySize);
+ privateKey = d2i_PrivateKey(EVP_PKEY_EC, &privateKey, (const unsigned char **) &bytes, keySize);
+
+ EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(privateKey);
+
+ *sig = parcMemory_Allocate(ECDSA_size(ec_key));
+ assertNotNull(sig, "parcMemory_Allocate(%u) returned NULL", ECDSA_size(ec_key));
+
+ *sigLength = 0;
+ PARCBuffer *bb_digest = parcCryptoHash_GetDigest(digestToSign);
+ int result = ECDSA_sign(opensslDigestType,
+ (unsigned char *) parcByteArray_Array(parcBuffer_Array(bb_digest)),
+ (int) parcBuffer_Remaining(bb_digest),
+ *sig,
+ sigLength,
+ ec_key);
+ assertTrue(result == 1, "Got error from ECDSA_sign: %d", result);
+ EC_KEY_free(ec_key);
+
+}
+
+static PARCSignature *
+_SignDigest(PARCPublicKeySigner *signer, const PARCCryptoHash *digestToSign)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(signer, "Parameter must be non-null CCNxFileKeystore");
+ assertNotNull(digestToSign, "Buffer to sign must not be null");
+
+ // TODO: what is the best way to expose this?
+ PARCKeyStore *keyStore = signer->keyStore;
+ PARCBuffer *privateKeyBuffer = parcKeyStore_GetDEREncodedPrivateKey(keyStore);
+
+ int opensslDigestType;
+ uint8_t *sig;
+ unsigned sigLength;
+
+ switch (parcCryptoHash_GetDigestType(digestToSign)) {
+ case PARCCryptoHashType_SHA256:
+ opensslDigestType = NID_sha256;
+ break;
+ case PARCCryptoHashType_SHA512:
+ opensslDigestType = NID_sha512;
+ break;
+ default:
+ trapUnexpectedState("Unknown digest type: %s",
+ parcCryptoHashType_ToString(parcCryptoHash_GetDigestType(digestToSign)));
+ }
+
+ switch (signer->signingAlgorithm) {
+ case PARCSigningAlgorithm_RSA:
+ _SignDigestRSA(digestToSign, privateKeyBuffer, opensslDigestType, &sig, &sigLength);
+ break;
+ case PARCSigningAlgorithm_ECDSA:
+ _SignDigestECDSA(digestToSign, privateKeyBuffer, opensslDigestType, &sig, &sigLength);
+ break;
+ default:
+ return NULL;
+ }
+
+ PARCBuffer *bbSign = parcBuffer_Allocate(sigLength);
+ parcBuffer_Flip(parcBuffer_PutArray(bbSign, sigLength, sig));
+ parcMemory_Deallocate((void **) &sig);
+
+ PARCSignature *signature =
+ parcSignature_Create(_GetSigningAlgorithm(signer),
+ parcCryptoHash_GetDigestType(digestToSign),
+ bbSign
+ );
+ parcBuffer_Release(&bbSign);
+ parcBuffer_Release(&privateKeyBuffer);
+ return signature;
+}
+
+static size_t
+_GetSignatureSize(PARCPublicKeySigner *signer)
+{
+ assertNotNull(signer, "Parameter must be non-null CCNxFileKeystore");
+
+ // TODO: what is the best way to expose this?
+ PARCKeyStore *keyStore = signer->keyStore;
+ PARCBuffer *privateKeyBuffer = parcKeyStore_GetDEREncodedPrivateKey(keyStore);
+
+ size_t size = 0;
+ switch (signer->signingAlgorithm) {
+ case PARCSigningAlgorithm_RSA:
+ {
+ EVP_PKEY *privateKey = NULL;
+ uint8_t *bytes = parcBuffer_Overlay(privateKeyBuffer, parcBuffer_Limit(privateKeyBuffer));
+ privateKey = d2i_PrivateKey(EVP_PKEY_RSA, &privateKey, (const unsigned char **) &bytes, parcBuffer_Limit(privateKeyBuffer));
+
+ RSA *rsa = EVP_PKEY_get1_RSA(privateKey);
+
+ size = RSA_size(rsa);
+ RSA_free(rsa);
+ EVP_PKEY_free(privateKey);
+ break;
+ }
+ case PARCSigningAlgorithm_ECDSA:
+ {
+ EVP_PKEY *privateKey = NULL;
+ size_t keySize = parcBuffer_Remaining(privateKeyBuffer);
+ uint8_t *bytes = parcBuffer_Overlay(privateKeyBuffer, keySize);
+ privateKey = d2i_PrivateKey(EVP_PKEY_EC, &privateKey, (const unsigned char **) &bytes, keySize);
+
+ EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(privateKey);
+
+ size = ECDSA_size(ec_key);
+ EC_KEY_free(ec_key);
+ EVP_PKEY_free(privateKey);
+ break;
+ }
+ }
+ parcBuffer_Release(&privateKeyBuffer);
+
+ return size;
+}
+
+PARCSigningInterface *PARCPublicKeySignerAsSigner = &(PARCSigningInterface) {
+ .GetCryptoHasher = (PARCCryptoHasher * (*)(void *))_GetCryptoHasher,
+ .SignDigest = (PARCSignature * (*)(void *, const PARCCryptoHash *))_SignDigest,
+ .GetSigningAlgorithm = (PARCSigningAlgorithm (*)(void *))_GetSigningAlgorithm,
+ .GetCryptoHashType = (PARCCryptoHashType (*)(void *))_GetCryptoHashType,
+ .GetKeyStore = (PARCKeyStore * (*)(void *))_GetKeyStore,
+ .GetSignatureSize = (size_t (*)(void *))_GetSignatureSize
+};
diff --git a/libparc/parc/security/parc_PublicKeySigner.h b/libparc/parc/security/parc_PublicKeySigner.h
new file mode 100644
index 00000000..ed98a39e
--- /dev/null
+++ b/libparc/parc/security/parc_PublicKeySigner.h
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_PublicKeySigner.h
+ * @brief An entity to produce digital signatures based on public/private key stores.
+ *
+ */
+#ifndef PARCLibrary_parc_PublicKeySigner
+#define PARCLibrary_parc_PublicKeySigner
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+#include <parc/security/parc_KeyStore.h>
+#include <parc/security/parc_CryptoHash.h>
+#include <parc/security/parc_CryptoSuite.h>
+#include <parc/security/parc_SigningAlgorithm.h>
+#include <parc/security/parc_Signer.h>
+
+struct PARCPublicKeySigner;
+typedef struct PARCPublicKeySigner PARCPublicKeySigner;
+
+extern PARCSigningInterface *PARCPublicKeySignerAsSigner;
+
+/**
+ * Increase the number of references to a `PARCPublicKeySigner` instance.
+ *
+ * Note that new `PARCPublicKeySigner` is not created,
+ * only that the given `PARCPublicKeySigner` reference count is incremented.
+ * Discard the reference by invoking `parcPublicKeySigner_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCPublicKeySigner instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * PARCPublicKeySigner *b = parcPublicKeySigner_Acquire();
+ *
+ * parcPublicKeySigner_Release(&a);
+ * parcPublicKeySigner_Release(&b);
+ * }
+ * @endcode
+ */
+PARCPublicKeySigner *parcPublicKeySigner_Acquire(const PARCPublicKeySigner *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcPublicKeySigner_OptionalAssertValid(_instance_)
+#else
+# define parcPublicKeySigner_OptionalAssertValid(_instance_) parcPublicKeySigner_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCPublicKeySigner` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCPublicKeySigner instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * parcPublicKeySigner_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcPublicKeySigner_Release(&b);
+ * }
+ * @endcode
+ */
+void parcPublicKeySigner_AssertValid(const PARCPublicKeySigner *instance);
+
+/**
+ * Create an instance of PARCPublicKeySigner
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCPublicKeySigner instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * parcPublicKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+PARCPublicKeySigner *parcPublicKeySigner_Create(PARCKeyStore *keyStore, PARCCryptoSuite suite);
+
+/**
+ * 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 PARCPublicKeySigner instance.
+ * @param [in] other A pointer to a valid PARCPublicKeySigner 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
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ * PARCPublicKeySigner *b = parcPublicKeySigner_Create();
+ *
+ * if (parcPublicKeySigner_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcPublicKeySigner_Release(&a);
+ * parcPublicKeySigner_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcPublicKeySigner_Equals
+ */
+int parcPublicKeySigner_Compare(const PARCPublicKeySigner *instance, const PARCPublicKeySigner *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 PARCPublicKeySigner instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCPublicKeySigner` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * PARCPublicKeySigner *copy = parcPublicKeySigner_Copy(&b);
+ *
+ * parcPublicKeySigner_Release(&b);
+ * parcPublicKeySigner_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCPublicKeySigner *parcPublicKeySigner_Copy(const PARCPublicKeySigner *original);
+
+/**
+ * Determine if two `PARCPublicKeySigner` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCPublicKeySigner` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcPublicKeySigner_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcPublicKeySigner_Equals(x, y)` must return true if and only if
+ * `parcPublicKeySigner_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcPublicKeySigner_Equals(x, y)` returns true and
+ * `parcPublicKeySigner_Equals(y, z)` returns true,
+ * then `parcPublicKeySigner_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcPublicKeySigner_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcPublicKeySigner_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCPublicKeySigner instance.
+ * @param [in] y A pointer to a valid PARCPublicKeySigner instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ * PARCPublicKeySigner *b = parcPublicKeySigner_Create();
+ *
+ * if (parcPublicKeySigner_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcPublicKeySigner_Release(&a);
+ * parcPublicKeySigner_Release(&b);
+ * }
+ * @endcode
+ * @see parcPublicKeySigner_HashCode
+ */
+bool parcPublicKeySigner_Equals(const PARCPublicKeySigner *x, const PARCPublicKeySigner *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 parcPublicKeySigner_Equals} method,
+ * then calling the {@link parcPublicKeySigner_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 parcPublicKeySigner_Equals} function,
+ * then calling the `parcPublicKeySigner_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCPublicKeySigner instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * PARCHashCode hashValue = parcPublicKeySigner_HashCode(buffer);
+ * parcPublicKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcPublicKeySigner_HashCode(const PARCPublicKeySigner *instance);
+
+/**
+ * Determine if an instance of `PARCPublicKeySigner` 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 PARCPublicKeySigner instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * if (parcPublicKeySigner_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcPublicKeySigner_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcPublicKeySigner_IsValid(const PARCPublicKeySigner *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCPublicKeySigner` 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
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * parcPublicKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+void parcPublicKeySigner_Release(PARCPublicKeySigner **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCPublicKeySigner 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
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * PARCJSON *json = parcPublicKeySigner_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcPublicKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcPublicKeySigner_ToJSON(const PARCPublicKeySigner *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCPublicKeySigner`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCPublicKeySigner 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
+ * {
+ * PARCPublicKeySigner *a = parcPublicKeySigner_Create();
+ *
+ * char *string = parcPublicKeySigner_ToString(a);
+ *
+ * parcPublicKeySigner_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcPublicKeySigner_Display
+ */
+char *parcPublicKeySigner_ToString(const PARCPublicKeySigner *instance);
+#endif
diff --git a/libparc/parc/security/parc_SecureRandom.c b/libparc/parc/security/parc_SecureRandom.c
new file mode 100644
index 00000000..8ebf7f0f
--- /dev/null
+++ b/libparc/parc/security/parc_SecureRandom.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 <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/security/parc_SecureRandom.h>
+
+struct parc_securerandom {
+ int randomfd;
+};
+
+static bool
+_parcSecureRandom_Destructor(PARCSecureRandom **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCSecureRandom pointer.");
+ PARCSecureRandom *instance = *instancePtr;
+
+ close(instance->randomfd);
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcSecureRandom, PARCSecureRandom);
+parcObject_ImplementRelease(parcSecureRandom, PARCSecureRandom);
+parcObject_Override(PARCSecureRandom, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcSecureRandom_Destructor);
+
+void
+parcSecureRandom_AssertValid(const PARCSecureRandom *instance)
+{
+ assertTrue(parcSecureRandom_IsValid(instance),
+ "PARCSecureRandom is not valid.");
+}
+
+PARCSecureRandom *
+parcSecureRandom_Create()
+{
+ PARCSecureRandom *result = NULL;
+
+ int fd = open("/dev/urandom", O_RDWR);
+ if (fd != -1) {
+ result = parcObject_CreateInstance(PARCSecureRandom);
+ if (result != NULL) {
+ result->randomfd = fd;
+ } else {
+ close(fd);
+ }
+ }
+
+ return result;
+}
+
+static void
+_parcSecureRandom_ReSeed(PARCSecureRandom *random, PARCBuffer *buffer)
+{
+ size_t length = parcBuffer_Remaining(buffer);
+ write(random->randomfd, parcBuffer_Overlay(buffer, length), length);
+}
+
+PARCSecureRandom *
+parcSecureRandom_CreateWithSeed(PARCBuffer *seed)
+{
+ PARCSecureRandom *result = parcSecureRandom_Create();
+
+ if (result != NULL) {
+ _parcSecureRandom_ReSeed(result, seed);
+ }
+
+ return result;
+}
+
+uint32_t
+parcSecureRandom_Next(PARCSecureRandom *random)
+{
+ uint32_t value;
+ read(random->randomfd, &value, sizeof(value));
+ return value;
+}
+
+ssize_t
+parcSecureRandom_NextBytes(PARCSecureRandom *random, PARCBuffer *buffer)
+{
+ size_t length = parcBuffer_Remaining(buffer);
+ ssize_t result = read(random->randomfd, parcBuffer_Overlay(buffer, 0), length);
+ return result;
+}
+
+bool
+parcSecureRandom_IsValid(const PARCSecureRandom *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ if (instance->randomfd != -1) {
+ result = true;
+ }
+ }
+
+ return result;
+}
diff --git a/libparc/parc/security/parc_SecureRandom.h b/libparc/parc/security/parc_SecureRandom.h
new file mode 100644
index 00000000..e5c67fc3
--- /dev/null
+++ b/libparc/parc/security/parc_SecureRandom.h
@@ -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.
+ */
+
+
+/**
+ * @file parc_SecureRandom.h
+ * @brief A cryptographically secure pseudorandom number generator that reads
+ * from a secure randomness source on the system, e.g., /dev/urandom.
+ *
+ */
+#ifndef Libparc_parc_SecureRandom
+#define Libparc_parc_SecureRandom
+
+#include <stdbool.h>
+
+#include <parc/algol/parc_Object.h>
+
+struct parc_securerandom;
+typedef struct parc_securerandom PARCSecureRandom;
+
+/**
+ * Increase the number of references to a `PARCSecureRandom` instance.
+ *
+ * Note that new `PARCSecureRandom` is not created,
+ * only that the given `PARCSecureRandom` reference count is incremented.
+ * Discard the reference by invoking `parcSecureRandom_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCSecureRandom instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSecureRandom *a = parcSecureRandom_Create();
+ *
+ * PARCSecureRandom *b = parcSecureRandom_Acquire();
+ *
+ * parcSecureRandom_Release(&a);
+ * parcSecureRandom_Release(&b);
+ * }
+ * @endcode
+ */
+PARCSecureRandom *parcSecureRandom_Acquire(const PARCSecureRandom *instance);
+
+/**
+ * Create an instance of PARCSecureRandom
+ *
+ * @return non-NULL A pointer to a valid PARCSecureRandom instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSecureRandom *rng = parcSecureRandom_Create();
+ *
+ * parcSecureRandom_Release(&rng);
+ * }
+ * @endcode
+ */
+PARCSecureRandom *parcSecureRandom_Create(void);
+
+/**
+ * Create an instance of PARCSecureRandom with a specific seed stored in
+ * a `PARCBuffer` instance.
+ *
+ * @param [in] seed A `PARCBuffer` instance.
+ *
+ * @return non-NULL A pointer to a valid PARCSecureRandom instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *seed = ...
+ * PARCSecureRandom *rng = parcSecureRandom_CreateWithSeed(seed);
+ *
+ * parcSecureRandom_Release(&rng);
+ * }
+ * @endcode
+ */
+PARCSecureRandom *parcSecureRandom_CreateWithSeed(PARCBuffer *seed);
+
+/**
+ * Generate a 32-bit unsigned integer from a `PARCSecureRandom` instance.
+ *
+ * @param [in] rng A `PARCSecureRandom` instance.
+ *
+ * @return non-NULL A pointer to a valid PARCSecureRandom instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSecureRandom *rng = parcSecureRandom_Create();
+ *
+ * uint32_t nextWord = parcSecureRandom_Next(rng);
+ * // use the word
+ * }
+ * @endcode
+ */
+uint32_t parcSecureRandom_Next(PARCSecureRandom *rng);
+
+/**
+ * Fill a `PARCBuffer` instance with random bytes from a `PARCSecureRandom` instance.
+ * The resultant `PARCBuffer` will be ready for reading, i.e., one does not need
+ * to call `parcBuffer_Flip()` on the result.
+ *
+ * @param [in] rng A `PARCSecureRandom` instance.
+ * @param [in] buffer A `PARCBuffer` instance to fill.
+ *
+ * @return non-NULL A pointer to a valid PARCSecureRandom instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSecureRandom *rng = parcSecureRandom_Create();
+ *
+ * PARCBuffer *buffer = parcBuffer_Allocate(32);
+ * ssize_t numBytes = parcSecureRandom_NextBytes(rng, buffer);
+ * // use the buffer
+ * }
+ * @endcode
+ */
+ssize_t parcSecureRandom_NextBytes(PARCSecureRandom *rng, PARCBuffer *buffer);
+
+/**
+ * Determine if an instance of `PARCSecureRandom` 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 PARCSecureRandom instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSecureRandom *rng = parcSecureRandom_Create();
+ *
+ * if (parcSecureRandom_IsValid(rng)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcSecureRandom_Release(&rng);
+ * }
+ * @endcode
+ *
+ */
+bool parcSecureRandom_IsValid(const PARCSecureRandom *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCSecureRandom` 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
+ * {
+ * PARCSecureRandom *rng = parcSecureRandom_Create();
+ *
+ * parcSecureRandom_Release(&rng);
+ * }
+ * @endcode
+ */
+void parcSecureRandom_Release(PARCSecureRandom **instancePtr);
+#endif
diff --git a/libparc/parc/security/parc_Security.c b/libparc/parc/security/parc_Security.c
new file mode 100644
index 00000000..70731ba3
--- /dev/null
+++ b/libparc/parc/security/parc_Security.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.
+ */
+
+/**
+ *
+ * June 9, 2014 add openssl multithreaded support.
+ * See http://www.openssl.org/docs/crypto/threads.html.
+ * We need to implement locking_function() and threadid_func().
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <stdbool.h>
+
+#include <pthread.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <openssl/opensslv.h>
+#include <openssl/err.h>
+#include <openssl/crypto.h>
+
+#define OPENSSL_THREAD_DEFINES
+#include <openssl/opensslconf.h>
+#if !defined(OPENSSL_THREADS)
+#error OpenSSL must support threads
+#endif
+
+// OPENSSL_VERSION_NUMBER = MMNNFFPPS
+// MM = major NN = minor FF = fix PP = patch S = 0 (dev), 1-E (betas), F (release)
+// This will require 1.0.1e release minimum version
+//#if OPENSSL_VERSION_NUMBER < 0x1000105fL
+#if OPENSSL_VERSION_NUMBER < 0x0009081fL
+#pragma message(OPENSSL_VERSION_TEXT)
+#error OpenSSL version must be at least 0.9.8 release
+#endif
+
+// Use the LongBow aids for this (case 999)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+#include <openssl/evp.h>
+#include <openssl/err.h>
+
+/*
+ * OpenSSL requires one lock per thread, so we have a global lock array
+ */
+static pthread_mutex_t *perThreadLocks;
+
+static volatile bool parcSecurity_initialized = false;
+static unsigned long parcSecurity_count = 0;
+
+pthread_mutex_t parcSecurity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void
+_lockingCallback(int mode, int type, const char *file __attribute__((unused)), int line __attribute__((unused)))
+{
+ int error = 0;
+ if (mode & CRYPTO_LOCK) {
+ error = pthread_mutex_lock(&(perThreadLocks[type]));
+ } else {
+ error = pthread_mutex_unlock(&(perThreadLocks[type]));
+ }
+
+ assertTrue(error == 0, "Error in pthreads: (%d) %s", errno, strerror(errno));
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x1000005fL
+
+// for older pre-1.0 versions of openssl
+static unsigned long
+_getThreadId(void)
+{
+ // Now, do the "right thing" with it. Some systems return a pointer to a struct
+ // and other systems return a native type. OpenSSL (1.0 or later) provide two
+ // mapping functions to convert these types of representations to CRYPTO_THREADID.
+#if defined(__APPLE__)
+ uint64_t threadid = 0;
+ int error = pthread_threadid_np(pthread_self(), &threadid);
+ assertTrue(error == 0, "Error getting threadid");
+ return (unsigned long) threadid;
+#elif defined(__linux__)
+ // linux (at least ubuntu and redhat) uses unsigned long int
+ pthread_t threadid = pthread_self();
+ return (unsigned long) threadid;
+#else
+#error Unsupported platform, only __APPLE__ and __linux__ supported
+#endif
+}
+
+#else
+
+// For new 1.0 or later versions of openssl
+static void
+_getThreadId(CRYPTO_THREADID *id)
+{
+ pthread_t threadid = pthread_self();
+
+ // Now, do the "right thing" with it. Some systems return a pointer to a struct
+ // and other systems return a native type. OpenSSL (1.0 or later) provide two
+ // mapping functions to convert these types of representations to CRYPTO_THREADID.
+
+#if defined(__APPLE__)
+ // The Apple Mac OS X pthreads uses a pointer to a struct (struct _opaque_pthread_t)
+ CRYPTO_THREADID_set_pointer(id, threadid);
+#elif defined(__linux__)
+ // linux (at least ubuntu and redhat) uses unsigned long int
+ CRYPTO_THREADID_set_numeric(id, threadid);
+#else
+#error Unsupported platform, only __APPLE__ and __linux__ supported
+#endif
+}
+#endif
+
+static void
+_initLocks(void)
+{
+ perThreadLocks = parcMemory_AllocateAndClear(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
+ assertNotNull(perThreadLocks, "parcMemory_AllocateAndClear(%zu) returned NULL",
+ CRYPTO_num_locks() * sizeof(pthread_mutex_t));
+
+ for (int i = 0; i < CRYPTO_num_locks(); i++) {
+ pthread_mutex_init(&(perThreadLocks[i]), NULL);
+ }
+
+#if OPENSSL_VERSION_NUMBER < 0x1000005fL
+ // for older pre-1.0 versions
+ CRYPTO_set_id_callback(_getThreadId);
+#else
+ CRYPTO_THREADID_set_callback(_getThreadId);
+#endif
+
+ CRYPTO_set_locking_callback(_lockingCallback);
+}
+
+static void
+_finiLocks(void)
+{
+ CRYPTO_set_locking_callback(NULL);
+ for (int i = 0; i < CRYPTO_num_locks(); i++) {
+ pthread_mutex_destroy(&(perThreadLocks[i]));
+ }
+ parcMemory_Deallocate((void **) &perThreadLocks);
+}
+
+void
+parcSecurity_AssertIsInitialized(void)
+{
+ trapUnexpectedStateIf(parcSecurity_IsInitialized() == false, "PARC Security framework is not initialized. See parcSecurity_Init()");
+}
+
+void
+parcSecurity_Init(void)
+{
+ int lockSuccessful = pthread_mutex_lock(&parcSecurity_mutex) == 0;
+ assertTrue(lockSuccessful, "Unable to lock the PARC Security framework.");
+
+ if (!parcSecurity_initialized) {
+ _initLocks();
+ OpenSSL_add_all_algorithms();
+ ERR_load_crypto_strings();
+
+ parcSecurity_initialized = true;
+ }
+ parcSecurity_count++;
+
+ int unlockSuccessful = pthread_mutex_unlock(&parcSecurity_mutex) == 0;
+ assertTrue(unlockSuccessful, "Unable to unlock the PARC Security framework.");
+}
+
+bool
+parcSecurity_IsInitialized(void)
+{
+ return parcSecurity_initialized;
+}
+
+void
+parcSecurity_Fini(void)
+{
+ int lockSuccessful = pthread_mutex_lock(&parcSecurity_mutex) == 0;
+ assertTrue(lockSuccessful, "Unable to lock the PARC Security framework.");
+
+ parcSecurity_count--;
+ if (parcSecurity_count == 0) {
+ EVP_cleanup();
+ ERR_free_strings();
+ parcSecurity_initialized = false;
+ _finiLocks();
+ }
+
+ int unlockSuccessful = pthread_mutex_unlock(&parcSecurity_mutex) == 0;
+ assertTrue(unlockSuccessful, "Unable to unlock the PARC Security framework.");
+}
+
+#pragma GCC diagnostic pop
diff --git a/libparc/parc/security/parc_Security.h b/libparc/parc/security/parc_Security.h
new file mode 100755
index 00000000..2c20496b
--- /dev/null
+++ b/libparc/parc/security/parc_Security.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 parc_Security.h
+ * @ingroup security
+ * @brief PARC Security Library framework director.
+ *
+ */
+#ifndef libparc_parc_Security_h
+#define libparc_parc_Security_h
+
+#include <stdbool.h>
+
+/**
+ * Initialise the PARC Security framework.
+ *
+ * This function may be called multiple times,
+ * each time incrementing a reference count that is decremented by calls to `parcSecurityFini`.
+ *
+ * Example:
+ * @code
+ * {
+ * parcSecurity_Init();
+ * }
+ * @endcode
+ *
+ * @see parcSecurity_Fini
+ */
+void parcSecurity_Init(void);
+
+/**
+ * Deinitialise the PARC Security framework.
+ *
+ * Example:
+ * @code
+ * {
+ * parcSecurity_Fini();
+ * }
+ * @endcode
+ *
+ * @see parcSecurity_Init
+ */
+void parcSecurity_Fini(void);
+
+/**
+ * Assert that the PARC Security Framework is initalised.
+ *
+ * Example:
+ * @code
+ * {
+ * parcSecurity_AssertIsInitialized();
+ *
+ * }
+ * @endcode
+ *
+ * @see parcSecurity_Init
+ */
+void parcSecurity_AssertIsInitialized(void);
+
+/**
+ * Determine if the PARC Security Framework is initalised.
+ *
+ * @return True if the PARC Security Framework is initalised.
+ * @return False otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * parcSecurity_IsInitialized();
+ * }
+ * @endcode
+ *
+ * @see parcSecurity_Init
+ */
+bool parcSecurity_IsInitialized(void);
+#endif // libparc_parc_Security_h
diff --git a/libparc/parc/security/parc_Signature.c b/libparc/parc/security/parc_Signature.c
new file mode 100755
index 00000000..1021b2a4
--- /dev/null
+++ b/libparc/parc/security/parc_Signature.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 <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/security/parc_Signature.h>
+#include <parc/algol/parc_Memory.h>
+
+struct parc_signature {
+ PARCSigningAlgorithm signingAlgorithm;
+ PARCCryptoHashType hashType;
+ PARCBuffer *signatureBits;
+};
+
+static void
+_parcSignature_FinalRelease(PARCSignature **signatureP)
+{
+ parcBuffer_Release(&(*signatureP)->signatureBits);
+}
+
+parcObject_ExtendPARCObject(PARCSignature, _parcSignature_FinalRelease, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCSignature *
+parcSignature_Create(PARCSigningAlgorithm signingAlgorithm, PARCCryptoHashType hashType, PARCBuffer *signatureBits)
+{
+ assertNotNull(signatureBits, "SignatureBits Parameter cannot be null");
+
+ PARCSignature *signature = parcObject_CreateInstance(PARCSignature);
+ assertNotNull(signature, "parcObject_CreateInstance(%zu) returned NULL", sizeof(PARCSignature));
+
+ signature->signingAlgorithm = signingAlgorithm;
+ signature->hashType = hashType;
+ signature->signatureBits = parcBuffer_Acquire(signatureBits);
+
+ return signature;
+}
+
+parcObject_ImplementAcquire(parcSignature, PARCSignature);
+
+parcObject_ImplementRelease(parcSignature, PARCSignature);
+
+
+PARCSigningAlgorithm
+parcSignature_GetSigningAlgorithm(const PARCSignature *signature)
+{
+ assertNotNull(signature, "Parameter must be non-null");
+ return signature->signingAlgorithm;
+}
+
+PARCCryptoHashType
+parcSignature_GetHashType(const PARCSignature *signature)
+{
+ assertNotNull(signature, "Parameter must be non-null");
+ return signature->hashType;
+}
+
+PARCBuffer *
+parcSignature_GetSignature(const PARCSignature *signature)
+{
+ assertNotNull(signature, "Parameter must be non-null");
+ return signature->signatureBits;
+}
+
+char *
+parcSignature_ToString(const PARCSignature *signature)
+{
+ assertNotNull(signature, "Parameter must be a non-null CCNxSignature pointer");
+
+ char *bits = parcBuffer_ToString(signature->signatureBits);
+
+ char *string;
+ int nwritten = asprintf(&string, "CCNxSignedInfo { .signingAlg=%d, .digestAlg=%d, .signature=%s }",
+ signature->signingAlgorithm,
+ signature->hashType,
+ bits);
+ assertTrue(nwritten >= 0, "Error calling asprintf");
+
+ parcMemory_Deallocate((void **) &bits);
+
+ char *result = parcMemory_StringDuplicate(string, strlen(string));
+ free(string);
+ return result;
+}
+
+bool
+parcSignature_Equals(const PARCSignature *x, const PARCSignature *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ if (x->signingAlgorithm == y->signingAlgorithm) {
+ if (x->hashType == y->hashType) {
+ if (parcBuffer_Equals(x->signatureBits, y->signatureBits)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/libparc/parc/security/parc_Signature.h b/libparc/parc/security/parc_Signature.h
new file mode 100755
index 00000000..3d28ac56
--- /dev/null
+++ b/libparc/parc/security/parc_Signature.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 parc_Signature.h
+ * @ingroup security
+ * @brief A tuple of (SigningAlgorithm, SignatureBuffer, PublicKeyDigest)
+ *
+ * A PARCSignature wraps the tuple { SigningAlgorithm, SignatureBuffer, PublicKeyDigest },
+ * where PublicKeyDigest is a PARCCryptoHash of the publisher public key digest.
+ *
+ */
+#ifndef libparc_parc_Signature_h
+#define libparc_parc_Signature_h
+
+#include <parc/security/parc_CryptoHash.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_SigningAlgorithm.h>
+#include <parc/algol/parc_Buffer.h>
+
+struct parc_signature;
+typedef struct parc_signature PARCSignature;
+
+/**
+ * Create a `PARCSignature` instance wrapping all the pieces needed to use it.
+ *
+ * @param [in] signingAlgorithm is the algorithm used to produce the signature
+ * @param [in] hashType The PARCCryptoHashType of cryptographic hash digest computed from the input bits which is ultimately signed.
+ * @param [in] signatureBits is the actual signature, as an array of bytes
+ *
+ * @return A pointer to a `PARCSignature` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *sigbits = parcBuffer_Flip(parcBuffer_FromString("signature bits"));
+ *
+ * PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ * parcBuffer_Release(&sigbits);
+ * }
+ * @endcode
+ */
+PARCSignature *parcSignature_Create(PARCSigningAlgorithm signingAlgorithm, PARCCryptoHashType hashType, PARCBuffer *signatureBits);
+
+/**
+ * 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 `parcSignature_Release`.
+ *
+ * @param [in] signature A pointer to the instance of `PARCSignature` to acquire.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * ...
+ *
+ * PARCSignature *signature = parcSignature_Acquire(instance);
+ *
+ * parcSignature_Release(&signature);
+ * }
+ * @endcode
+ *
+ * @see `parcSignature_Release`
+ */
+
+PARCSignature *parcSignature_Acquire(const PARCSignature *signature);
+
+/**
+ * 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] signaturePtr A pointer to a pointer to the instance to release.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *sigbits = parcBuffer_Flip(parcBuffer_FromString("signature bits"));
+ *
+ * PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ * parcBuffer_Release(&sigbits);
+ * parcSignature_Release(&signature);
+ * }
+ * @endcode
+ *
+ * @see `parcSignature_Acquire`
+ */
+void parcSignature_Release(PARCSignature **signaturePtr);
+
+/**
+ * Returns the signing algorithm.
+ *
+ * @param [in] signature The `PARCSignature` instance from which the signing algorithm is retrieved.
+ *
+ * @return A `PARCSigningAlgorithm` value corresponding to this signature.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *sigbits = parcBuffer_Flip(parcBuffer_FromString("signature bits"));
+ *
+ * PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ * parcBuffer_Release(&sigbits);
+ *
+ * PARCSigningAlgorithm algorithm = parcSignature_GetSigningAlgorithm(signature);
+ * }
+ * @endcode
+ */
+PARCSigningAlgorithm parcSignature_GetSigningAlgorithm(const PARCSignature *signature);
+
+/**
+ * Returns the digest algorithm used to compute the digest we signed.
+ *
+ * @param [in] signature The `PARCSignature` instance from which the hash type is retrieved.
+ *
+ * @return A `PARCCryptoHashType` value corresponding to this signature.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *sigbits = parcBuffer_Flip(parcBuffer_FromString("signature bits"));
+ *
+ * PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ * parcBuffer_Release(&sigbits);
+ *
+ * PARCCryptoHashType hashType = parcSignature_GetHashType(signature);
+ * }
+ * @endcode
+ */
+PARCCryptoHashType parcSignature_GetHashType(const PARCSignature *signature);
+
+/**
+ * Gets the signature as a buffer of bits.
+ *
+ * @param [in] signature The `PARCSignature` instance from which the signature payload is retrieved.
+ *
+ * @return A `PARCBuffer` instanace containing the raw signature bytes.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *sigbits = parcBuffer_Flip(parcBuffer_FromString("signature bits"));
+ *
+ * PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ * parcBuffer_Release(&sigbits);
+ *
+ * PARCBuffer *payload = parcSignature_GetSignature(signature);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcSignature_GetSignature(const PARCSignature *signature);
+
+/**
+ * Produce a nul-terminated string representation of the specified instance.
+ *
+ * The non-null result must be freed by the caller via `parcMemory_Deallocate()`.
+ *
+ * @param [in] signature A pointer to a PARCSignature instance.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a nul-terminated C-string the must be dellocated via `parcMemory_Deallocate()`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *sigbits = parcBuffer_Flip(parcBuffer_FromString("signature bits"));
+ *
+ * PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ * parcBuffer_Release(&sigbits);
+ *
+ * char *string = parcSignature_ToString(signature);
+ *
+ * parcMemory_Deallocate(&signature);
+ * }
+ * @endcode
+ */
+char *parcSignature_ToString(const PARCSignature *signature);
+
+/**
+ * Determine if two PARCSignature instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCSignature` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `parcSignature_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `parcSignature_Equals(x, y)` must return true if and only if
+ * `parcSignature_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcSignature_Equals(x, y)` returns true and
+ * `parcSignature_Equals(y, z)` returns true,
+ * then `parcSignature_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `parcSignature_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `parcSignature_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param [in] a A pointer to a PARCSignature instance.
+ * @param [in] b A pointer to a PARCSignature instance.
+ *
+ * @return true if the two instances are equal
+ * @return false if the two instancea are no equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *sigbits = parcBuffer_Flip(parcBuffer_FromString("signature bits"));
+ *
+ * PARCSignature *signatureA = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ * PARCSignature *signatureB = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, sigbits);
+ * parcBuffer_Release(&sigbits);
+ *
+ * if (parcSignature_Equals(signatureA, signatureB)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * parcMemory_Deallocate(&signatureA);
+ * parcMemory_Deallocate(&signatureB);
+ * }
+ * @endcode
+ */
+bool parcSignature_Equals(const PARCSignature *a, const PARCSignature *b);
+#endif // libparc_parc_Signature_h
diff --git a/libparc/parc/security/parc_Signer.c b/libparc/parc/security/parc_Signer.c
new file mode 100644
index 00000000..5287c97b
--- /dev/null
+++ b/libparc/parc/security/parc_Signer.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/algol/parc_Object.h>
+
+#include <parc/security/parc_Signer.h>
+#include <parc/security/parc_KeyStore.h>
+
+struct parc_signer {
+ PARCObject *instance;
+ PARCSigningInterface *interface;
+};
+
+static bool
+_parcSigner_FinalRelease(PARCSigner **signerPtr)
+{
+ PARCSigner *signer = *signerPtr;
+ if (signer->instance != NULL) {
+ parcObject_Release(&(signer->instance));
+ }
+ return true;
+}
+
+void
+parcSigner_AssertValid(const PARCSigner *signer)
+{
+ assertNotNull(signer, "Parameter must be non-null PARCSigner");
+}
+
+parcObject_ImplementAcquire(parcSigner, PARCSigner);
+parcObject_ImplementRelease(parcSigner, PARCSigner);
+
+parcObject_Override(PARCSigner, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcSigner_FinalRelease);
+
+PARCSigner *
+parcSigner_Create(PARCObject *instance, PARCSigningInterface *interfaceContext)
+{
+ assertNotNull(interfaceContext, "Parameter must be non-null implementation pointer");
+
+ PARCSigner *signer = parcObject_CreateInstance(PARCSigner);
+ if (signer != NULL) {
+ signer->instance = parcObject_Acquire(instance);
+ signer->interface = interfaceContext;
+ }
+ return signer;
+}
+
+PARCKey *
+parcSigner_CreatePublicKey(PARCSigner *signer)
+{
+ PARCKeyStore *keyStore = parcSigner_GetKeyStore(signer);
+
+ PARCCryptoHash *hash = parcKeyStore_GetVerifierKeyDigest(keyStore);
+
+ PARCKeyId *keyid = parcKeyId_Create(parcCryptoHash_GetDigest(hash));
+ parcCryptoHash_Release(&hash);
+
+ PARCBuffer *derEncodedKey = parcKeyStore_GetDEREncodedPublicKey(keyStore);
+
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid,
+ parcSigner_GetSigningAlgorithm(signer),
+ derEncodedKey);
+
+ parcBuffer_Release(&derEncodedKey);
+ parcKeyId_Release(&keyid);
+
+ return key;
+}
+
+PARCKeyId *
+parcSigner_CreateKeyId(const PARCSigner *signer)
+{
+ PARCCryptoHash *hash = parcKeyStore_GetVerifierKeyDigest(parcSigner_GetKeyStore(signer));
+ PARCBuffer *keyidBytes = parcCryptoHash_GetDigest(hash);
+ PARCKeyId *result = parcKeyId_Create(keyidBytes);
+
+ parcCryptoHash_Release(&hash);
+ return result;
+}
+
+PARCCryptoHasher *
+parcSigner_GetCryptoHasher(const PARCSigner *signer)
+{
+ parcSigner_OptionalAssertValid(signer);
+
+ return signer->interface->GetCryptoHasher(signer->instance);
+}
+
+PARCSignature *
+parcSigner_SignDigest(const PARCSigner *signer, const PARCCryptoHash *parcDigest)
+{
+ parcSigner_OptionalAssertValid(signer);
+
+ assertNotNull(parcDigest, "parcDigest to sign must not be null");
+ return signer->interface->SignDigest(signer->instance, parcDigest);
+}
+
+PARCSignature *
+parcSigner_SignBuffer(const PARCSigner *signer, const PARCBuffer *buffer)
+{
+ parcSigner_OptionalAssertValid(signer);
+ assertNotNull(buffer, "buffer to sign must not be null");
+
+ PARCCryptoHashType hashType = parcSigner_GetCryptoHashType(signer);
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(hashType);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBuffer(hasher, buffer);
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+ parcCryptoHasher_Release(&hasher);
+
+ PARCSignature *signature = parcSigner_SignDigest(signer, hash);
+ parcCryptoHash_Release(&hash);
+
+ return signature;
+}
+
+PARCSigningAlgorithm
+parcSigner_GetSigningAlgorithm(PARCSigner *signer)
+{
+ parcSigner_OptionalAssertValid(signer);
+
+ return signer->interface->GetSigningAlgorithm(signer->instance);
+}
+
+PARCCryptoHashType
+parcSigner_GetCryptoHashType(const PARCSigner *signer)
+{
+ parcSigner_OptionalAssertValid(signer);
+
+ return signer->interface->GetCryptoHashType(signer->instance);
+}
+
+PARCCryptoSuite
+parcSigner_GetCryptoSuite(const PARCSigner *signer)
+{
+ parcSigner_OptionalAssertValid(signer);
+
+ PARCCryptoHashType hash = signer->interface->GetCryptoHashType(signer->instance);
+ PARCSigningAlgorithm signAlgo = signer->interface->GetSigningAlgorithm(signer->instance);
+ return parcCryptoSuite_GetFromSigningHash(signAlgo, hash);
+}
+
+PARCKeyStore *
+parcSigner_GetKeyStore(const PARCSigner *signer)
+{
+ parcSigner_OptionalAssertValid(signer);
+
+ return signer->interface->GetKeyStore(signer->instance);
+}
+
+size_t
+parcSigner_GetSignatureSize(const PARCSigner *signer)
+{
+ parcSigner_OptionalAssertValid(signer);
+
+ return signer->interface->GetSignatureSize(signer->instance);
+}
diff --git a/libparc/parc/security/parc_Signer.h b/libparc/parc/security/parc_Signer.h
new file mode 100755
index 00000000..1e675c50
--- /dev/null
+++ b/libparc/parc/security/parc_Signer.h
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Signer.h
+ * @ingroup security
+ * @brief The API a crytography provider must interfaceement.
+ *
+ * A signer IS NOT THREAD-SAFE.
+ *
+ */
+#ifndef libparc_parc_Signer_h
+#define libparc_parc_Signer_h
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/security/parc_CryptoHasher.h>
+#include <parc/security/parc_CryptoSuite.h>
+#include <parc/security/parc_Signature.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_Key.h>
+#include <parc/security/parc_KeyStore.h>
+
+struct parc_signer;
+/**
+ * @typedef PARCSigner
+ * @brief The structure for PARCSigner
+ */
+
+typedef struct parc_signer PARCSigner;
+
+/**
+ * @def parcSigner_OptionalAssertValid
+ * Optional validation of the given instance.
+ *
+ * Define `PARCLibrary_DISABLE_VALIDATION` to disable validation.
+ */
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcSigner_OptionalAssertValid(_instance_)
+#else
+# define parcSigner_OptionalAssertValid(_instance_) parcSigner_AssertValid(_instance_)
+#endif
+
+/**
+ * @typedef PARCSigningInterface
+ * @brief The CCN signing implementation structure.
+ *
+ * This defines the contract that any concrete implementation provides.
+ *
+ */
+typedef struct parc_signer_interface {
+ /**
+ * Returns a the hasher to use for the signature. This is important for
+ * symmetric key HMAC to use this hasher, not one from PARCCryptoHasher.
+ *
+ * DO NOT DESTROY THIS HASHER! Just call _Init, _Update, and _Finalize.
+ *
+ * The hash type will be based on how the underlying implementation was initialized
+ *
+ * Equivalent of (for rsa/sha256)
+ * openssl rsautl -sign -inkey test_rsa_key.pem -in infile_digest -out infile.sig
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCSigner instance.
+ */
+ PARCCryptoHasher *(*GetCryptoHasher)(void *interfaceContext);
+
+ /**
+ * Compute the signature of the given PARCCryptoHash.
+ *
+ * Equivalent of (for rsa/sha256)
+ * openssl rsautl -sign -inkey test_rsa_key.pem -in infile_digest -out infile.sig
+ *
+ * @param [in] interfaceContextPtr A pointer to a concrete PARCSigner instance.
+ * @param [in] hashToSign The output of the given digest to sign
+ *
+ * @return A pointer to a PARCSignature instance that must be released via parcSignature_Release()
+ */
+ PARCSignature *(*SignDigest)(void *interfaceContext, const PARCCryptoHash * parcDigest);
+
+ /**
+ * Return the PARSigningAlgorithm used for signing with the given `PARCSigner`
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCSigner instance.
+ *
+ * @return A PARSigningAlgorithm value.
+ */
+ PARCSigningAlgorithm (*GetSigningAlgorithm)(void *interfaceContext);
+
+ /**
+ * Return the digest algorithm used by the Signer
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCSigner instance.
+ *
+ * @return A PARCCryptoHashType value.
+ */
+ PARCCryptoHashType (*GetCryptoHashType)(void *interfaceContext);
+
+ /**
+ * Return the PARCKeyStore for this Signer.
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCSigner instance.
+ *
+ * @return A PARCKeyStore instance.
+ */
+ PARCKeyStore *(*GetKeyStore)(void *interfaceContext);
+
+ /**
+ * Return the key size for this Signer.
+ *
+ * @param [in] interfaceContext A pointer to a concrete PARCSigner instance.
+ *
+ * @return A size_t
+ */
+ size_t (*GetSignatureSize)(void *interfaceContext);
+} PARCSigningInterface;
+
+/**
+ * Assert that an instance of `PARCSigner` 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] signer A pointer to a PARCSigner instance.
+ *
+ * Example
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner);
+ *
+ * parcSigner_AssertValid(signer);
+ * }
+ * @endcode
+ */
+void parcSigner_AssertValid(const PARCSigner *signer);
+
+/**
+ * Create a signing context based on a concrete implementation.
+ *
+ * @param [in] instance A concrete implementation of a `PARCSigner`
+ * @param [in] interfaceContext The interface of a concrete implementation of a `PARCSigner`
+ *
+ * @return NULL A `PARCSigner` could not be allocated
+ * @return PARCSigner A new `PARCSigner` instance derived from the specified concrete signer context.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner);
+ * }
+ * @endcode
+ */
+PARCSigner *parcSigner_Create(PARCObject *instance, PARCSigningInterface *interfaceContext);
+
+/**
+ * Increase the number of references to the given `PARCSigner` instance.
+ *
+ * A new instance is not created,
+ * only that the given instance's reference count is incremented.
+ * Discard the acquired reference by invoking `parcSigner_Release()`.
+ *
+ * @param [in] signer A pointer to a `PARCSigner` instance.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a PARCSigner instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner);
+ * PARCSigner *handle = parcSigner_Acquire(signer);
+ * // use the handle instance as needed
+ * }
+ * @endcode
+ */
+PARCSigner *parcSigner_Acquire(const PARCSigner *signer);
+
+/**
+ * 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.
+ *
+ * The contents of the dealloced memory used for the PARC object are undefined.
+ * Do not reference the object after the last release.
+ *
+ * @param [in,out] signerPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner);
+ *
+ * parcSigner_Release(&signer);
+ * }
+ * @endcode
+ */
+void parcSigner_Release(PARCSigner **signerPtr);
+
+/**
+ * Create a PARCKeyId instance from the given pinter to a `PARCSigner` instance.
+ *
+ * @param [in] signer A pointer to a PARCSigner instance.
+ *
+ * @return A pointer to a created PARCKeyId instance that must be released via `parcKeyId_Release()`
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner);
+ *
+ * PARCKeyId *keyId = parcSigner_CreateKeyId(signer);
+ * }
+ * @endcode
+ */
+PARCKeyId *parcSigner_CreateKeyId(const PARCSigner *signer);
+
+/**
+ * Get the DER encoded public key and keyid wrapped in a `PARCKey` instance.
+ *
+ * @param [in] signer A pointer to a PARCSigner instance.
+ *
+ * @return A newly allocated `PARCKey` instance containing the public key used to verify signatures computed by this signer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner);
+ *
+ * PARCKey *publicKey = parcSigner_CreatePublicKey(signer);
+ * }
+ * @endcode
+ */
+PARCKey *parcSigner_CreatePublicKey(PARCSigner *signer);
+
+/**
+ * Returns a the hasher to use for the signature. This is important for
+ * symmetric key HMAC to use this hasher, not one from PARCCryptoHasher.
+ *
+ * DO NOT DESTROY THIS HASHER! Just call _Init, _Update, and _Finalize.
+ *
+ * The hash type will be based on how the underlying implementation was initialized
+ *
+ * Equivalent of (for rsa/sha256)
+ * openssl rsautl -sign -inkey test_rsa_key.pem -in infile_digest -out infile.sig
+ *
+ * @param [in] signer A pointer to a PARCSigner instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner);
+ *
+ * PARCCryptoHasher hasher = parcSigner_GetCryptoHasher(signer);
+ * }
+ * @endcode
+ */
+PARCCryptoHasher *parcSigner_GetCryptoHasher(const PARCSigner *signer);
+
+/**
+ * Compute the signature of the given PARCCryptoHash.
+ *
+ * Equivalent of (for rsa/sha256)
+ * openssl rsautl -sign -inkey test_rsa_key.pem -in infile_digest -out infile.sig
+ *
+ * @param [in] signer A pointer to a PARCSigner instance.
+ * @param [in] hashToSign The output of the given digest
+ *
+ * @return A pointer to a PARCSignature instance that must be released via parcSignature_Release()
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner);
+ *
+ * PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer);
+ * parcCryptoHasher_Init(hasher);
+ * parcCryptoHasher_Update_Bytes(hasher, &block->memory[relativePosition], length);
+ * PARCCryptoHash *hashToSign = parcCryptoHasher_Finalize(hasher);
+ *
+ * PARCSignature signature = parcSigner_SignDigest(signer, hashToSign);
+ * }
+ * @endcode
+ */
+PARCSignature *parcSigner_SignDigest(const PARCSigner *signer, const PARCCryptoHash *hashToSign);
+
+/**
+ * Compute the signature of a given `PARCBuffer`.
+ *
+ * @param [in] signer A pointer to a PARCSigner instance.
+ * @param [in] buffer The input to be hashed and signed.
+ *
+ * @return A pointer to a PARCSignature instance that must be released via parcSignature_Release()
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner);
+ * PARCBuffer *inputBuffer = ...
+ *
+ * PARCSignature signature = parcSigner_SignBuffer(signer, inputBuffer);
+ * }
+ * @endcode
+ */
+PARCSignature *parcSigner_SignBuffer(const PARCSigner *signer, const PARCBuffer *buffer);
+
+/**
+ * Return the PARSigningAlgorithm used for signing with the given `PARCSigner`
+ *
+ * @param [in] signer A pointer to a PARCSigner instance.
+ *
+ * @return A PARSigningAlgorithm value.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner);
+ *
+ * PARCSigningAlgorithm suite = parcSigner_GetSigningAlgorithm(signer);
+ * }
+ * @endcode
+ */
+PARCSigningAlgorithm parcSigner_GetSigningAlgorithm(PARCSigner *signer);
+
+/**
+ * Return the digest algorithm used by the Signer
+ *
+ * @param [in] signer A pointer to a PARCSigner instance.
+ *
+ * @return A PARCCryptoHashType value.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner);
+ *
+ * PARCCryptoHashType suite = parcSigner_GetCryptoHashType(signer);
+ * }
+ * @endcode
+ */
+PARCCryptoHashType parcSigner_GetCryptoHashType(const PARCSigner *signer);
+
+/**
+ * Return the crypto suite used by the Signer
+ *
+ * @param [in] signer A pointer to a PARCSigner instance.
+ *
+ * @return A PARCCryptoSuite value.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner);
+ *
+ * PARCCryptoSuite suite = parcSigner_GetCryptoSuite(signer);
+ * }
+ * @endcode
+ */
+PARCCryptoSuite parcSigner_GetCryptoSuite(const PARCSigner *signer);
+
+/**
+ * Given a `PARCSigner` instance, return the `PARCKeyStore` containing its public key information.
+ *
+ * @param [in] signer A pointer to a `PARCSigner` instance.
+ *
+ * @return A `PARCKeyStore` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner);
+ *
+ * PARCKeyStore *keyStore = parcSigner_GetKeyStore(signer);
+ * }
+ * @endcode
+ */
+PARCKeyStore *parcSigner_GetKeyStore(const PARCSigner *signer);
+
+/**
+ * Given a `PARCSigner` instance, return the expected size of the signature.
+ *
+ * @param [in] signer A pointer to a `PARCSigner` instance.
+ *
+ * @return A size_t with the size of the key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCRSASignerAsSigner);
+ *
+ * PARCKeyStore *keyStore = parcSigner_GetKeyStore(signer);
+ * }
+ * @endcode
+ */
+size_t parcSigner_GetSignatureSize(const PARCSigner *signer);
+#endif // libparc_parc_Signer_h
diff --git a/libparc/parc/security/parc_SigningAlgorithm.c b/libparc/parc/security/parc_SigningAlgorithm.c
new file mode 100755
index 00000000..5803f675
--- /dev/null
+++ b/libparc/parc/security/parc_SigningAlgorithm.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 <string.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_SigningAlgorithm.h>
+
+static struct {
+ PARCSigningAlgorithm alg;
+ char *name;
+} _signingAlgorithm_ToString[] = {
+ { PARCSigningAlgorithm_NULL, "PARCSigningAlgorithm_NULL" },
+ { PARCSigningAlgorithm_RSA, "PARCSigningAlgorithm_RSA" },
+ { PARCSigningAlgorithm_DSA, "PARCSigningAlgorithm_DSA" },
+ { PARCSigningAlgorithm_HMAC, "PARCSigningAlgorithm_HMAC" },
+ { PARCSigningAlgorithm_ECDSA,"PARCSigningAlgorithm_ECDSA"},
+ { 0, NULL }
+};
+
+const char *
+parcSigningAlgorithm_ToString(PARCSigningAlgorithm alg)
+{
+ for (int i = 0; _signingAlgorithm_ToString[i].name != NULL; i++) {
+ if (_signingAlgorithm_ToString[i].alg == alg) {
+ return _signingAlgorithm_ToString[i].name;
+ }
+ }
+ return NULL;
+}
+
+PARCSigningAlgorithm
+parcSigningAlgorithm_FromString(const char *name)
+{
+ for (int i = 0; _signingAlgorithm_ToString[i].name != NULL; i++) {
+ if (strcmp(_signingAlgorithm_ToString[i].name, name) == 0) {
+ return _signingAlgorithm_ToString[i].alg;
+ }
+ }
+ return PARCSigningAlgorithm_UNKNOWN;
+}
diff --git a/libparc/parc/security/parc_SigningAlgorithm.h b/libparc/parc/security/parc_SigningAlgorithm.h
new file mode 100644
index 00000000..12265c8a
--- /dev/null
+++ b/libparc/parc/security/parc_SigningAlgorithm.h
@@ -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.
+ */
+
+/**
+ * @file parc_SigningAlgorithm.h
+ * @ingroup security
+ * @brief This module encapsulates information about the types of available signing algorithms.
+ *
+ * Both asymmetric digital signature algorithms, e.g., RSA and DSA, and symmetric Message Authentication
+ * Codes (MACS), e.g., HMAC, are supported. This module exposes the functionality necessary to map between
+ * enum and human-readable string representations of these algorithms.
+ *
+ */
+#ifndef libparc_parc_SigningAlgorithm_h
+#define libparc_parc_SigningAlgorithm_h
+
+typedef enum {
+ PARCSigningAlgorithm_UNKNOWN = -1,
+ PARCSigningAlgorithm_RSA = 1,
+ PARCSigningAlgorithm_DSA = 2,
+ PARCSigningAlgorithm_HMAC = 3,
+ PARCSigningAlgorithm_ECDSA = 4,
+ PARCSigningAlgorithm_NULL = 5,
+} PARCSigningAlgorithm;
+
+/**
+ * Return a human readable string representation of the specified signing algorithm.
+ *
+ * @param [in] algorithm A pointer to a PARCSigningAlgorithm as the target signing algorithm.
+ * @return A static, null-terminated string.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSigningAlgorithm alg = PARCSigningAlgorithm_RSA;
+ * const char *stringRep = parcSigningAlgorithm_ToString(alg);
+ * // do something with stringRep
+ * }
+ * @endcode
+ *
+ * @see parcSigningAlgorithm_FromString
+ */
+const char *parcSigningAlgorithm_ToString(PARCSigningAlgorithm algorithm);
+
+/**
+ * Get the `PARCSigningAlgorithm` enum from a corresponding human-readable string representation
+ * of a signing algorithm.
+ *
+ * @param [in] name A nul-terminate C-string representation of signing algorithm.
+ * @return A valid `PARCSigningAlgorithm` enum.
+ *
+ * Example:
+ * @code
+ * {
+ * const char *stringRep = "PARCSigningAlgortihm_NULL";
+ * PARCSigningAlgorithm alg = parcSigningAlgorithm_FromString(stringRep);
+ * // do something with alg
+ * }
+ * @endcode
+ *
+ * @see parcSigningAlgorithm_ToString
+ */
+PARCSigningAlgorithm parcSigningAlgorithm_FromString(const char *name);
+
+#endif // libparc_parc_SigningAlgorithm_h
diff --git a/libparc/parc/security/parc_SymmetricKeySigner.c b/libparc/parc/security/parc_SymmetricKeySigner.c
new file mode 100644
index 00000000..b06389dd
--- /dev/null
+++ b/libparc/parc/security/parc_SymmetricKeySigner.c
@@ -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.
+ */
+
+
+/**
+ */
+#include <config.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/security/parc_Signer.h>
+#include <parc/security/parc_SymmetricKeySigner.h>
+#include <parc/security/parc_KeyStore.h>
+
+#include <openssl/opensslv.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/safestack.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+#include <openssl/rand.h>
+#include <openssl/aes.h>
+#include <openssl/hmac.h>
+
+#define AES_KEYSTORE_VERSION 1L
+#define IV_SIZE 16
+#define AES_MAX_DIGEST_SIZE 128
+#define AES_DEFAULT_DIGEST_ALGORITHM "SHA256"
+
+struct PARCSymmetricKeySigner {
+ PARCSymmetricKeyStore *keyStore;
+ PARCKeyStore *generalKeyStore;
+
+ PARCCryptoHash *secretKeyHash;
+ PARCCryptoHasher *hasher;
+ PARCCryptoHasherInterface hasherFunctor;
+ PARCCryptoHashType hashType;
+
+ unsigned hashLength;
+ const EVP_MD *opensslMd;
+};
+
+// ==================================================
+// HMAC implementation
+
+static void *
+_hmacCreate(void *env)
+{
+ PARCSymmetricKeySigner *signer = (PARCSymmetricKeySigner *) env;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_CTX *ctx = HMAC_CTX_new();
+ HMAC_CTX_reset(ctx);
+#else
+ // HMAC_Init_ex seems to overrun the size of HMAC_CTX, so make it bigger
+ HMAC_CTX *ctx = parcMemory_Allocate(sizeof(HMAC_CTX) * 2);
+ assertNotNull(ctx, "parcMemory_Allocate(%zu) returned NULL for HMAC_CTX", sizeof(HMAC_CTX) * 2);
+ HMAC_CTX_init(ctx);
+#endif
+
+ // Now initialize it with our digest and key, so in hmac_init we can avoid using those
+ PARCBuffer *secretKey = parcSymmetricKeyStore_GetKey(signer->keyStore);
+ assertTrue(parcBuffer_Remaining(secretKey) < 512, "The keystore secret key cannot be longer than %d", 512);
+
+ HMAC_Init_ex(ctx, parcByteArray_Array(parcBuffer_Array(secretKey)), (int) parcBuffer_Remaining(secretKey), signer->opensslMd, NULL);
+
+ return ctx;
+}
+
+static int
+_hmacInit(void *ctx)
+{
+ // reset the HMAC state with NULLs, so we'll re-use the values we had from setup.
+ HMAC_Init_ex((HMAC_CTX *) ctx, NULL, 0, NULL, NULL);
+ return 0;
+}
+
+static int
+_hmacUpdate(void *ctx, const void *buffer, size_t length)
+{
+ HMAC_Update(ctx, buffer, length);
+ return 0;
+}
+
+static PARCBuffer*
+_hmacFinalize(void *ctx)
+{
+ uint8_t buffer[EVP_MAX_MD_SIZE];
+ unsigned length;
+ HMAC_Final(ctx, buffer, &length);
+
+ PARCBuffer *output = parcBuffer_Allocate(length);
+ parcBuffer_PutArray(output, length, buffer);
+
+ return output;
+}
+
+static void
+_hmacDestroy(void **ctxPtr)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x1010003fL)
+ HMAC_CTX_free(*ctxPtr);
+#else
+ HMAC_CTX_cleanup(*ctxPtr);
+ parcMemory_Deallocate((void **) ctxPtr);
+#endif
+ *ctxPtr = NULL;
+}
+
+static PARCCryptoHasherInterface functor_hmac = {
+ .functor_env = NULL,
+ .hasher_setup = _hmacCreate,
+ .hasher_init = _hmacInit,
+ .hasher_update = _hmacUpdate,
+ .hasher_finalize = _hmacFinalize,
+ .hasher_destroy = _hmacDestroy
+};
+
+static bool
+_parcSymmetricKeySigner_Finalize(PARCSymmetricKeySigner **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCSymmetricKeySigner pointer.");
+ PARCSymmetricKeySigner *signer = (PARCSymmetricKeySigner *) *instancePtr;
+ if (signer->secretKeyHash != NULL) {
+ parcCryptoHash_Release(&signer->secretKeyHash);
+ }
+ if (signer->hasher != NULL) {
+ parcCryptoHasher_Release(&signer->hasher);
+ }
+
+ if (signer->keyStore != NULL) {
+ parcSymmetricKeyStore_Release(&signer->keyStore);
+ }
+ if (signer->generalKeyStore != NULL) {
+ parcKeyStore_Release(&signer->generalKeyStore);
+ }
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcSymmetricKeySigner, PARCSymmetricKeySigner);
+parcObject_ImplementRelease(parcSymmetricKeySigner, PARCSymmetricKeySigner);
+
+parcObject_Override(PARCSymmetricKeySigner, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcSymmetricKeySigner_Finalize);
+
+void
+parcSymmetricKeySigner_AssertValid(const PARCSymmetricKeySigner *instance)
+{
+ assertTrue(parcSymmetricKeySigner_IsValid(instance),
+ "PARCSymmetricKeySigner is not valid.");
+}
+
+PARCSymmetricKeySigner *
+parcSymmetricKeySigner_Create(PARCSymmetricKeyStore *keyStore, PARCCryptoHashType hmacHashType)
+{
+ PARCSymmetricKeySigner *result = parcObject_CreateInstance(PARCSymmetricKeySigner);
+
+ if (result != NULL) {
+ result->hashType = hmacHashType;
+ switch (hmacHashType) {
+ case PARCCryptoHashType_SHA256:
+ result->hashLength = SHA256_DIGEST_LENGTH;
+ result->opensslMd = EVP_sha256();
+ break;
+
+ case PARCCryptoHashType_SHA512:
+ result->hashLength = SHA512_DIGEST_LENGTH;
+ result->opensslMd = EVP_sha512();
+ break;
+
+ default:
+ parcObject_Release((void **) &result);
+ trapIllegalValue(hmacHashType, "Unknown HMAC hash type: %d", hmacHashType);
+ }
+
+ // the signer key digest is SHA256, independent of the HMAC digest
+ result->secretKeyHash = parcSymmetricKeyStore_GetVerifierKeyDigest(keyStore);
+ result->keyStore = parcSymmetricKeyStore_Acquire(keyStore);
+ result->generalKeyStore = parcKeyStore_Create(result->keyStore, PARCSymmetricKeyStoreAsKeyStore);
+
+ // create the functor from the template then specialize it to this keystore.
+ // This depends on keystore->secret_key being set. It will cause a callback
+ // into hmac_setup()
+ result->hasherFunctor = functor_hmac;
+ result->hasherFunctor.functor_env = result;
+ result->hasher = parcCryptoHasher_CustomHasher(hmacHashType, result->hasherFunctor);
+ }
+
+ return result;
+}
+
+bool
+parcSymmetricKeySigner_IsValid(const PARCSymmetricKeySigner *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+static PARCSigningAlgorithm
+_getSigningAlgorithm(PARCSymmetricKeySigner *signer)
+{
+ return PARCSigningAlgorithm_HMAC;
+}
+
+static PARCCryptoHashType
+_getCryptoHashType(PARCSymmetricKeySigner *signer)
+{
+ return signer->hashType;
+}
+
+static PARCCryptoHasher *
+_getCryptoHasher(PARCSymmetricKeySigner *signer)
+{
+ return signer->hasher;
+}
+
+static PARCKeyStore *
+_getKeyStore(PARCSymmetricKeySigner *signer)
+{
+ return signer->generalKeyStore;
+}
+
+static size_t
+_GetSignatureSize(PARCSymmetricKeySigner *signer)
+{
+ assertNotNull(signer, "Parameter must be non-null CCNxFileKeystore");
+
+ // TODO: what is the best way to expose this?
+ PARCSymmetricKeyStore *keyStore = signer->keyStore;
+ PARCBuffer *secretKeyBuffer = parcSymmetricKeyStore_GetKey(keyStore);
+
+ return parcBuffer_Limit(secretKeyBuffer);
+}
+
+// ==================================================
+// implementation
+
+/**
+ * wrap the HMAC in digestToSign in a PARCSignature
+ *
+ * @param hashToSign is the HMAC computed by the our PARCCryptoHasher.
+ */
+static PARCSignature *
+_signDigest(PARCSymmetricKeySigner *interfaceContext, const PARCCryptoHash *hashToSign)
+{
+ // The digest computed via our hash function (hmac) is the actual signature.
+ // just need to wrap it up with the right parameters.
+ PARCBuffer *signatureBits = parcBuffer_Copy(parcCryptoHash_GetDigest(hashToSign));
+ PARCSignature *result = parcSignature_Create(_getSigningAlgorithm(interfaceContext), parcCryptoHash_GetDigestType(hashToSign), signatureBits);
+ parcBuffer_Release(&signatureBits);
+ return result;
+}
+
+PARCSigningInterface *PARCSymmetricKeySignerAsSigner = &(PARCSigningInterface) {
+ .GetCryptoHashType = (PARCCryptoHashType (*)(void *))_getCryptoHashType,
+ .GetCryptoHasher = (PARCCryptoHasher * (*)(void *))_getCryptoHasher,
+ .SignDigest = (PARCSignature * (*)(void *, const PARCCryptoHash *))_signDigest,
+ .GetSigningAlgorithm = (PARCSigningAlgorithm (*)(void *))_getSigningAlgorithm,
+ .GetKeyStore = (PARCKeyStore * (*)(void *))_getKeyStore,
+ .GetSignatureSize = (size_t (*)(void *))_GetSignatureSize
+};
diff --git a/libparc/parc/security/parc_SymmetricKeySigner.h b/libparc/parc/security/parc_SymmetricKeySigner.h
new file mode 100644
index 00000000..ab4b59f2
--- /dev/null
+++ b/libparc/parc/security/parc_SymmetricKeySigner.h
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_SymmetricKeySigner.h
+ * @brief A symmetric-key signer that creates MAC tags.
+ */
+#ifndef Libparc_parc_SymmetricKeySigner
+#define Libparc_parc_SymmetricKeySigner
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+#include <parc/security/parc_SymmetricKeyStore.h>
+
+struct PARCSymmetricKeySigner;
+typedef struct PARCSymmetricKeySigner PARCSymmetricKeySigner;
+
+extern PARCSigningInterface *PARCSymmetricKeySignerAsSigner;
+
+/**
+ * Increase the number of references to a `PARCSymmetricKeySigner` instance.
+ *
+ * Note that new `PARCSymmetricKeySigner` is not created,
+ * only that the given `PARCSymmetricKeySigner` reference count is incremented.
+ * Discard the reference by invoking `parcSymmetricKeySigner_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCSymmetricKeySigner instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * PARCSymmetricKeySigner *b = parcSymmetricKeySigner_Acquire();
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ * parcSymmetricKeySigner_Release(&b);
+ * }
+ * @endcode
+ */
+PARCSymmetricKeySigner *parcSymmetricKeySigner_Acquire(const PARCSymmetricKeySigner *instance);
+
+#ifdef Libparc_DISABLE_VALIDATION
+# define parcSymmetricKeySigner_OptionalAssertValid(_instance_)
+#else
+# define parcSymmetricKeySigner_OptionalAssertValid(_instance_) parcSymmetricKeySigner_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCSymmetricKeySigner` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCSymmetricKeySigner instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * parcSymmetricKeySigner_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcSymmetricKeySigner_Release(&b);
+ * }
+ * @endcode
+ */
+void parcSymmetricKeySigner_AssertValid(const PARCSymmetricKeySigner *instance);
+
+/**
+ * Create an instance of PARCSymmetricKeySigner
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCSymmetricKeySigner instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+PARCSymmetricKeySigner *parcSymmetricKeySigner_Create(PARCSymmetricKeyStore *keyStore, PARCCryptoHashType hmacHashType);
+
+/**
+ * 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 PARCSymmetricKeySigner instance.
+ * @param [in] other A pointer to a valid PARCSymmetricKeySigner 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
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ * PARCSymmetricKeySigner *b = parcSymmetricKeySigner_Create();
+ *
+ * if (parcSymmetricKeySigner_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ * parcSymmetricKeySigner_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcSymmetricKeySigner_Equals
+ */
+int parcSymmetricKeySigner_Compare(const PARCSymmetricKeySigner *instance, const PARCSymmetricKeySigner *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 PARCSymmetricKeySigner instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCSymmetricKeySigner` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * PARCSymmetricKeySigner *copy = parcSymmetricKeySigner_Copy(&b);
+ *
+ * parcSymmetricKeySigner_Release(&b);
+ * parcSymmetricKeySigner_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCSymmetricKeySigner *parcSymmetricKeySigner_Copy(const PARCSymmetricKeySigner *original);
+
+/**
+ * Print a human readable representation of the given `PARCSymmetricKeySigner`.
+ *
+ * @param [in] instance A pointer to a valid PARCSymmetricKeySigner instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * parcSymmetricKeySigner_Display(a, 0);
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+void parcSymmetricKeySigner_Display(const PARCSymmetricKeySigner *instance, int indentation);
+
+/**
+ * Determine if two `PARCSymmetricKeySigner` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCSymmetricKeySigner` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcSymmetricKeySigner_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcSymmetricKeySigner_Equals(x, y)` must return true if and only if
+ * `parcSymmetricKeySigner_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcSymmetricKeySigner_Equals(x, y)` returns true and
+ * `parcSymmetricKeySigner_Equals(y, z)` returns true,
+ * then `parcSymmetricKeySigner_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcSymmetricKeySigner_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcSymmetricKeySigner_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCSymmetricKeySigner instance.
+ * @param [in] y A pointer to a valid PARCSymmetricKeySigner instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ * PARCSymmetricKeySigner *b = parcSymmetricKeySigner_Create();
+ *
+ * if (parcSymmetricKeySigner_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ * parcSymmetricKeySigner_Release(&b);
+ * }
+ * @endcode
+ * @see parcSymmetricKeySigner_HashCode
+ */
+bool parcSymmetricKeySigner_Equals(const PARCSymmetricKeySigner *x, const PARCSymmetricKeySigner *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 parcSymmetricKeySigner_Equals} method,
+ * then calling the {@link parcSymmetricKeySigner_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 parcSymmetricKeySigner_Equals} function,
+ * then calling the `parcSymmetricKeySigner_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCSymmetricKeySigner instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * PARCHashCode hashValue = parcSymmetricKeySigner_HashCode(buffer);
+ * parcSymmetricKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcSymmetricKeySigner_HashCode(const PARCSymmetricKeySigner *instance);
+
+/**
+ * Determine if an instance of `PARCSymmetricKeySigner` 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 PARCSymmetricKeySigner instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * if (parcSymmetricKeySigner_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcSymmetricKeySigner_IsValid(const PARCSymmetricKeySigner *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCSymmetricKeySigner` 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
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+void parcSymmetricKeySigner_Release(PARCSymmetricKeySigner **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCSymmetricKeySigner 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
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * PARCJSON *json = parcSymmetricKeySigner_ToJSON(a);
+ *
+ * printf("JSON representation: %s\n", parcJSON_ToString(json));
+ * parcJSON_Release(&json);
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcSymmetricKeySigner_ToJSON(const PARCSymmetricKeySigner *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCSymmetricKeySigner`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCSymmetricKeySigner 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
+ * {
+ * PARCSymmetricKeySigner *a = parcSymmetricKeySigner_Create();
+ *
+ * char *string = parcSymmetricKeySigner_ToString(a);
+ *
+ * parcSymmetricKeySigner_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcSymmetricKeySigner_Display
+ */
+char *parcSymmetricKeySigner_ToString(const PARCSymmetricKeySigner *instance);
+#endif // Libparc_parc_SymmetricKeySigner
diff --git a/libparc/parc/security/parc_SymmetricKeyStore.c b/libparc/parc/security/parc_SymmetricKeyStore.c
new file mode 100644
index 00000000..38996dba
--- /dev/null
+++ b/libparc/parc/security/parc_SymmetricKeyStore.c
@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ */
+/**
+ * To compute an HMAC, we need to interfaceement our own CryptoHasher so we can
+ * initialize it with the secret key
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/safestack.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+#include <openssl/rand.h>
+#include <openssl/aes.h>
+#include <openssl/hmac.h>
+
+#include <LongBow/runtime.h>
+#include <LongBow/longBow_Compiler.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_KeyStore.h>
+#include <parc/security/parc_SymmetricKeyStore.h>
+
+#define AES_KEYSTORE_VERSION 1L
+#define IV_SIZE 16
+#define AES_MAX_DIGEST_SIZE 128
+#define AES_DEFAULT_DIGEST_ALGORITHM "SHA256"
+
+struct parc_symmetric_keystore {
+ PARCBuffer *secretKey;
+};
+
+static PARCBuffer *
+_createDerivedKey(const char *key, size_t keylength, unsigned char *salt, unsigned int saltlen)
+{
+ unsigned char buffer[SHA256_DIGEST_LENGTH];
+ HMAC(EVP_sha256(), key, (int) keylength, salt, saltlen, buffer, NULL);
+ return parcBuffer_PutArray(parcBuffer_Allocate(SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH, buffer);
+}
+
+static PARCCryptoHash *
+_getSecretKeyDigest(PARCSymmetricKeyStore *keyStore)
+{
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Init(hasher);
+
+ parcCryptoHasher_UpdateBuffer(hasher, keyStore->secretKey);
+ PARCCryptoHash *result = parcCryptoHasher_Finalize(hasher);
+ parcCryptoHasher_Release(&hasher);
+
+ return result;
+}
+
+static bool
+_parcSymmetricKeyStore_Finalize(PARCSymmetricKeyStore **interfacePtr)
+{
+ PARCSymmetricKeyStore *keyStore = *interfacePtr;
+ if (keyStore->secretKey != NULL) {
+ parcBuffer_Release(&keyStore->secretKey);
+ }
+ return true;
+}
+
+PARCKeyStoreInterface *PARCSymmetricKeyStoreAsKeyStore = &(PARCKeyStoreInterface) {
+ .getVerifierKeyDigest = (PARCKeyStoreGetVerifierKeyDigest *) _getSecretKeyDigest,
+ .getCertificateDigest = NULL,
+ .getDEREncodedCertificate = NULL,
+ .getDEREncodedPublicKey = NULL,
+ .getDEREncodedPrivateKey = NULL,
+};
+
+parcObject_ImplementAcquire(parcSymmetricKeyStore, PARCSymmetricKeyStore);
+parcObject_ImplementRelease(parcSymmetricKeyStore, PARCSymmetricKeyStore);
+
+parcObject_Override(PARCSymmetricKeyStore, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcSymmetricKeyStore_Finalize);
+
+// =============================================================
+LONGBOW_STOP_DEPRECATED_WARNINGS
+// =============================================================
+
+/**
+ * The openssl ASN1 representation of the PARC symmetric key keystore.
+ * It will be written to disk in DER format with an i2d call
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+typedef struct PARCAESKeystore_info_st {
+ ASN1_INTEGER *version;
+ ASN1_OBJECT *algorithm_oid;
+ ASN1_OCTET_STRING *encrypted_key;
+} _PARCSymmeticSignerFileStoreInfo;
+
+// This generates a name that is not compliant with the PARC Naming conventions.
+DECLARE_ASN1_FUNCTIONS(_PARCSymmeticSignerFileStoreInfo)
+
+ASN1_SEQUENCE(_PARCSymmeticSignerFileStoreInfo) = {
+ ASN1_SIMPLE(_PARCSymmeticSignerFileStoreInfo, version, ASN1_INTEGER),
+ ASN1_SIMPLE(_PARCSymmeticSignerFileStoreInfo, algorithm_oid, ASN1_OBJECT),
+ ASN1_SIMPLE(_PARCSymmeticSignerFileStoreInfo, encrypted_key, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(_PARCSymmeticSignerFileStoreInfo)
+
+IMPLEMENT_ASN1_FUNCTIONS(_PARCSymmeticSignerFileStoreInfo)
+
+static int
+_i2d_AESKeystore_fp(FILE *fp, _PARCSymmeticSignerFileStoreInfo *aki)
+{
+ return ASN1_item_i2d_fp(ASN1_ITEM_rptr(_PARCSymmeticSignerFileStoreInfo), fp, aki);
+}
+
+static _PARCSymmeticSignerFileStoreInfo *
+_d2iAESKeystoreFp(FILE *fp, _PARCSymmeticSignerFileStoreInfo *aki)
+{
+ return ASN1_item_d2i_fp(ASN1_ITEM_rptr(_PARCSymmeticSignerFileStoreInfo), fp, aki);
+}
+
+static bool
+_createKeyStore(const char *filename, const char *password, PARCBuffer *key)
+{
+ FILE *fp = NULL;
+ int fd = -1;
+ int ans = -1;
+ int nid;
+
+ _PARCSymmeticSignerFileStoreInfo *keystore = NULL;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+#else
+ EVP_CIPHER_CTX ctx;
+#endif
+ unsigned char *encrypted_key = NULL;
+
+ int ekl = IV_SIZE + (int) parcBuffer_Remaining(key) + SHA256_DIGEST_LENGTH + AES_BLOCK_SIZE;
+ int encrypt_length;
+
+ fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0600);
+
+ if (fd == -1) {
+ goto Bail;
+ }
+ fp = fdopen(fd, "wb");
+ if (fp == NULL) {
+ goto Bail;
+ }
+
+ PARCBuffer *aes_key = _createDerivedKey(password, strlen(password), (unsigned char *) "\0", 1);
+ PARCBuffer *mac_key = _createDerivedKey(password, strlen(password), (unsigned char *) "\1", 1);
+
+ encrypted_key = malloc(ekl);
+ if (!encrypted_key) {
+ goto Bail;
+ }
+ RAND_bytes(encrypted_key, IV_SIZE);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ EVP_CIPHER_CTX_init(ctx);
+ if (!EVP_EncryptInit(ctx, EVP_aes_256_cbc(), parcByteArray_Array(parcBuffer_Array(aes_key)), encrypted_key)) {
+ goto Bail;
+ }
+
+ unsigned char *p;
+ p = encrypted_key + IV_SIZE;
+ if (!EVP_EncryptUpdate(ctx, p, &encrypt_length, parcByteArray_Array(parcBuffer_Array(key)), (int) parcBuffer_Remaining(key))) {
+ goto Bail;
+ }
+ p += encrypt_length;
+ if (!EVP_EncryptFinal(ctx, p, &encrypt_length)) {
+ goto Bail;
+ }
+#else
+ EVP_CIPHER_CTX_init(&ctx);
+ if (!EVP_EncryptInit(&ctx, EVP_aes_256_cbc(), parcByteArray_Array(parcBuffer_Array(aes_key)), encrypted_key)) {
+ goto Bail;
+ }
+
+ unsigned char *p;
+ p = encrypted_key + IV_SIZE;
+ if (!EVP_EncryptUpdate(&ctx, p, &encrypt_length, parcByteArray_Array(parcBuffer_Array(key)), (int) parcBuffer_Remaining(key))) {
+ goto Bail;
+ }
+ p += encrypt_length;
+ if (!EVP_EncryptFinal(&ctx, p, &encrypt_length)) {
+ goto Bail;
+ }
+#endif
+ p += encrypt_length;
+ HMAC(EVP_sha256(), parcByteArray_Array(parcBuffer_Array(mac_key)), SHA256_DIGEST_LENGTH, encrypted_key, p - encrypted_key, p, NULL);
+
+ if (!(keystore = _PARCSymmeticSignerFileStoreInfo_new())) {
+ goto Bail;
+ }
+ if (!(keystore->version = ASN1_INTEGER_new())) {
+ goto Bail;
+ }
+ if (!ASN1_INTEGER_set(keystore->version, AES_KEYSTORE_VERSION)) {
+ goto Bail;
+ }
+
+ keystore->algorithm_oid = OBJ_txt2obj(AES_DEFAULT_DIGEST_ALGORITHM, 0);
+ nid = OBJ_obj2nid(keystore->algorithm_oid);
+ if (nid == NID_undef) {
+ goto Bail; // Shouldn't happen now but could later if we support more algorithms
+ }
+ if (!ASN1_OCTET_STRING_set(keystore->encrypted_key, encrypted_key, ekl)) {
+ goto Bail;
+ }
+ _i2d_AESKeystore_fp(fp, keystore);
+ ans = 0;
+ goto cleanup;
+
+ Bail:
+ ans = -1;
+ cleanup:
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ EVP_CIPHER_CTX_free(ctx);
+#endif
+ parcBuffer_Release(&aes_key);
+ parcBuffer_Release(&mac_key);
+
+ if (fp != NULL) {
+ fclose(fp);
+ }
+ if (encrypted_key) {
+ free(encrypted_key);
+ }
+ if (keystore) {
+ _PARCSymmeticSignerFileStoreInfo_free(keystore);
+ }
+ if (fd != -1) {
+ close(fd);
+ }
+ return (ans);
+}
+
+static PARCBuffer *
+_AESKeyStoreInit(const char *filename, const char *password)
+{
+ PARCBuffer *secret_key = NULL;
+
+ FILE *fp = NULL;
+ _PARCSymmeticSignerFileStoreInfo *ki = NULL;
+ int version;
+ char oidstr[80];
+
+ PARCBuffer *aes_key = NULL;
+ PARCBuffer *mac_key = NULL;
+
+ unsigned char check[SHA256_DIGEST_LENGTH];
+ unsigned char *keybuf = NULL;
+ int check_start;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+#else
+ EVP_CIPHER_CTX ctx;
+#endif
+ int length = 0;
+ int final_length = 0;
+
+ fp = fopen(filename, "rb");
+ if (fp == NULL) {
+ goto Bail;
+ }
+
+ ki = _d2iAESKeystoreFp(fp, NULL);
+ fclose(fp);
+ if (ki == NULL) {
+ goto Bail;
+ }
+
+ version = (int) ASN1_INTEGER_get(ki->version);
+ if (version != AES_KEYSTORE_VERSION) {
+ goto Bail;
+ }
+
+ OBJ_obj2txt(oidstr, sizeof(oidstr), ki->algorithm_oid, 0);
+ if (strcasecmp(oidstr, AES_DEFAULT_DIGEST_ALGORITHM)) {
+ goto Bail;
+ }
+
+ if (ki->encrypted_key->length < IV_SIZE + (SHA256_DIGEST_LENGTH * 2) + AES_BLOCK_SIZE) {
+ goto Bail;
+ }
+
+ aes_key = _createDerivedKey(password, strlen(password), (unsigned char *) "\0", 1);
+ mac_key = _createDerivedKey(password, strlen(password), (unsigned char *) "\1", 1);
+
+ check_start = ki->encrypted_key->length - SHA256_DIGEST_LENGTH;
+ HMAC(EVP_sha256(),
+ parcByteArray_Array(parcBuffer_Array(mac_key)),
+ SHA256_DIGEST_LENGTH,
+ ki->encrypted_key->data,
+ check_start,
+ check,
+ NULL);
+
+ if (memcmp(&ki->encrypted_key->data[check_start], check, SHA256_DIGEST_LENGTH)) {
+ goto Bail;
+ }
+ keybuf = malloc(SHA256_DIGEST_LENGTH + AES_BLOCK_SIZE);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ EVP_CIPHER_CTX_init(ctx);
+ if (!EVP_DecryptInit(ctx, EVP_aes_256_cbc(), parcByteArray_Array(parcBuffer_Array(aes_key)), ki->encrypted_key->data)) {
+ goto Bail;
+ }
+ if (!EVP_DecryptUpdate(ctx, keybuf, &length, &ki->encrypted_key->data[IV_SIZE],
+ ki->encrypted_key->length - IV_SIZE - SHA256_DIGEST_LENGTH)) {
+ goto Bail;
+ }
+
+ if (!EVP_DecryptFinal(ctx, keybuf + length, &final_length)) {
+ goto Bail;
+ }
+#else
+ EVP_CIPHER_CTX_init(&ctx);
+ if (!EVP_DecryptInit(&ctx, EVP_aes_256_cbc(), parcByteArray_Array(parcBuffer_Array(aes_key)), ki->encrypted_key->data)) {
+ goto Bail;
+ }
+ if (!EVP_DecryptUpdate(&ctx, keybuf, &length, &ki->encrypted_key->data[IV_SIZE],
+ ki->encrypted_key->length - IV_SIZE - SHA256_DIGEST_LENGTH)) {
+ goto Bail;
+ }
+
+ if (!EVP_DecryptFinal(&ctx, keybuf + length, &final_length)) {
+ goto Bail;
+ }
+#endif
+ secret_key = parcBuffer_CreateFromArray(keybuf, length);
+ parcBuffer_Flip(secret_key);
+
+ goto out;
+
+ Bail:
+ free(keybuf);
+
+ out:
+ if (aes_key) {
+ parcBuffer_Release(&aes_key);
+ }
+
+ if (mac_key) {
+ parcBuffer_Release(&mac_key);
+ }
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ EVP_CIPHER_CTX_free(ctx);
+#endif
+ return secret_key;
+}
+
+/**
+ * Create a symmetric (secret) key of the given bit length (e.g. 256)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *
+parcSymmetricKeyStore_CreateKey(unsigned bits)
+{
+ assertTrue((bits & 0x07) == 0, "bits must be a multiple of 8");
+
+ unsigned keylength = bits / 8;
+ uint8_t buffer[keylength];
+ RAND_bytes(buffer, keylength);
+ return parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(keylength), keylength, buffer));
+}
+
+PARCBuffer *
+parcSymmetricKeyStore_GetKey(PARCSymmetricKeyStore *keyStore)
+{
+ return keyStore->secretKey;
+}
+
+PARCCryptoHash *
+parcSymmetricKeyStore_GetVerifierKeyDigest(PARCSymmetricKeyStore *keyStore)
+{
+ return _getSecretKeyDigest(keyStore);
+}
+
+/**
+ * Creates a PARC format symmetric keystore. It only contains a single key.
+ *
+ * The final filename will be "file_prefix.
+ *
+ * Returns 0 on success, -1 on error.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool
+parcSymmetricKeyStore_CreateFile(const char *filename, const char *password, PARCBuffer *secret_key)
+{
+ assertTrue(parcBuffer_Remaining(secret_key) > 0, "The secret_key buffer is not flipped. See parcBuffer_Flip()");
+ return _createKeyStore(filename, password, secret_key) == 0;
+}
+
+/**
+ * Create a PKCS12 signing context for use in ccnx_Signing. It is destroyed
+ * by ccnx_Signing when the signing context is destroyed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCSymmetricKeyStore *
+parcSymmetricKeyStore_OpenFile(const char *filename, const char *password, PARCCryptoHashType hmacHashType)
+{
+ PARCBuffer *secretKey = _AESKeyStoreInit(filename, password);
+ assertNotNull(secretKey, "Could not read AES keystore %s", filename);
+
+ PARCSymmetricKeyStore *keyStore = parcSymmetricKeyStore_Create(secretKey);
+ parcBuffer_Release(&secretKey);
+
+ return keyStore;
+}
+
+/**
+ * Create a PKCS12 signing context for use in ccnx_Signing from the provided key. It is destroyed
+ * by parc_Signing when the signing context is destroyed.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCSymmetricKeyStore *
+parcSymmetricKeyStore_Create(PARCBuffer *secret_key)
+{
+ PARCSymmetricKeyStore *keyStore = parcObject_CreateAndClearInstance(PARCSymmetricKeyStore);
+ assertNotNull(keyStore, "parcObject_CreateAndClearInstance returned NULL, cannot allocate keystore");
+
+ keyStore->secretKey = parcBuffer_Acquire(secret_key);
+
+ return keyStore;
+}
+
+// =============================================================
+LONGBOW_START_DEPRECATED_WARNINGS
+// =============================================================
diff --git a/libparc/parc/security/parc_SymmetricKeyStore.h b/libparc/parc/security/parc_SymmetricKeyStore.h
new file mode 100644
index 00000000..3271b676
--- /dev/null
+++ b/libparc/parc/security/parc_SymmetricKeyStore.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_SymmetricKeyStore.h
+ * @ingroup security
+ * @brief A PARCKeyStore instance for symmetric keys that can be used to produce,
+ * for example, HMAC authenticator tags.
+ *
+ * The secret key is stored in a PARC proprietary file format.
+ *
+ * ---------------------------------------------------------------------------
+ * From the Java implementation code comments:
+ *
+ * This is a specialized keystore for storing symmetric keys. We looked at PKCS #11 for this but decided
+ * against it for now because industry doesn't seem to be standardizing around it - at least not yet, and
+ * standard support for it is somewhat sketchy at this point.
+ *
+ * The keystore can be used for only one key at a time and is located by naming it with a suffix
+ * created from the key's digest.
+ *
+ * Following is the formula for the KeyStore
+ *
+ * Let P=passphrase
+ * Let PT = symmetric key to store
+ * Let IV = random 16-bytes
+ *
+ * aesK = HMAC-SHA256(P, '\0')
+ * macK = HMAC-SHA256(P, '\1')
+ * AES256-CBC(IV, key, PT) - performs AES256 in CBC mode
+ *
+ * SK = IV || AES256-CBC(IV, aesK, PT) || HMAC-SHA256(macK, AES256-CBC(IV, aesK, PT))
+ *
+ * SK is the symmetric keystore ciphertext
+ *
+ * ASN1 encoded KeyStore = Version || Key algorithm OID || SK
+ * ---------------------------------------------------------------------------
+ *
+ */
+#ifndef libparc_parc_SymmetricKeyStore_h
+#define libparc_parc_SymmetricKeyStore_h
+
+#include <parc/security/parc_Signer.h>
+#include <parc/algol/parc_Buffer.h>
+
+struct parc_symmetric_keystore;
+typedef struct parc_symmetric_keystore PARCSymmetricKeyStore;
+
+extern PARCKeyStoreInterface *PARCSymmetricKeyStoreAsKeyStore;
+
+/**
+ * Increase the number of references to a `PARCSymmetricKeyStore` instance.
+ *
+ * Note that new `PARCSymmetricKeyStore` is not created,
+ * only that the given `PARCSymmetricKeyStore` reference count is incremented.
+ * Discard the reference by invoking `parcSymmetricKeyStore_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCSymmetricKeyStore instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * parcSymmetricKeyStore_CreateFile(...);
+ * PARCSymmetricKeyStore *a = parcSymmetricKeyStore_OpenFile(...)
+ *
+ * PARCSymmetricKeyStore *b = parcSymmetricKeyStore_Acquire();
+ *
+ * parcSymmetricKeyStore_Release(&a);
+ * parcSymmetricKeyStore_Release(&b);
+ * }
+ * @endcode
+ */
+PARCSymmetricKeyStore *parcSymmetricKeyStore_Acquire(const PARCSymmetricKeyStore *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCSymmetricKeyStore` 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
+ * {
+ * PARCSymmetricKeyStore *a = parcSymmetricKeyStore_Open(...);
+ *
+ * parcSymmetricKeyStore_Release(&a);
+ * }
+ * @endcode
+ */
+void parcSymmetricKeyStore_Release(PARCSymmetricKeyStore **instancePtr);
+
+/**
+ * Create a symmetric (secret) key of the given bit length (e.g. 256)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *parcSymmetricKeyStore_CreateKey(unsigned bits);
+
+PARCBuffer *parcSymmetricKeyStore_GetKey(PARCSymmetricKeyStore *keyStore);
+
+PARCCryptoHash *parcSymmetricKeyStore_GetVerifierKeyDigest(PARCSymmetricKeyStore *keyStore);
+
+/**
+ * Creates a PARC format symmetric keystore. It only contains a single key.
+ *
+ * Return 0 on success, -1 on failure
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool parcSymmetricKeyStore_CreateFile(const char *filename, const char *password, PARCBuffer *secret_key);
+
+/**
+ * Create a PKCS12 signing context for use in ccnx_Signing by reading the PARC symmetric key
+ * file given by filename. It is destroyed
+ * by parc_Signing when the signing context is destroyed.
+ *
+ * @param [in] filename The filename.
+ * @param [in] password The password to use.
+ * @param [in] hmacHashType is for the HMAC, e.g. PARCCryptoHashType_SHA256
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCSymmetricKeyStore *parcSymmetricKeyStore_OpenFile(const char *filename, const char *password, PARCCryptoHashType hmacHashType);
+
+/**
+ * Create a PKCS12 signing context for use in ccnx_Signing from the provided key.
+ * This is an in-memory only signer.
+ * It is destroyed by parc_Signing when the signing context is destroyed.
+ *
+ * @param secret_key is the shared secret, we take ownership of the buffer.
+ * @param hmacHashType is for the HMAC, e.g. PARCCryptoHashType_SHA256
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCSymmetricKeyStore *parcSymmetricKeyStore_Create(PARCBuffer *secret_key);
+#endif // libparc_parc_SymmetricKeyStore_h
diff --git a/libparc/parc/security/parc_Verifier.c b/libparc/parc/security/parc_Verifier.c
new file mode 100755
index 00000000..967356a5
--- /dev/null
+++ b/libparc/parc/security/parc_Verifier.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 <config.h>
+#include <stdio.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/security/parc_Verifier.h>
+#include <parc/algol/parc_Memory.h>
+
+struct parc_verifier {
+ PARCObject *instance;
+ PARCVerifierInterface *interface;
+};
+
+static bool
+_parcVerifier_FinalRelease(PARCVerifier **verifierPtr)
+{
+ PARCVerifier *verifier = *verifierPtr;
+ if (verifier->instance != NULL) {
+ parcObject_Release(&(verifier->instance));
+ }
+ return true;
+}
+
+void
+parcVerifier_AssertValid(const PARCVerifier *verifier)
+{
+ assertNotNull(verifier, "Parameter must be non-null PARCVerifier");
+}
+
+parcObject_ImplementAcquire(parcVerifier, PARCVerifier);
+parcObject_ImplementRelease(parcVerifier, PARCVerifier);
+
+parcObject_Override(PARCVerifier, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcVerifier_FinalRelease);
+
+PARCVerifier *
+parcVerifier_Create(PARCObject *instance, PARCVerifierInterface *interfaceContext)
+{
+ assertNotNull(interfaceContext, "Parameter `interfaceContext` must be non-null interface pointer");
+ assertNotNull(instance, "Parameter `instance` must be non-null PARCObject pointer");
+
+ PARCVerifier *verifier = parcObject_CreateInstance(PARCVerifier);
+ assertNotNull(verifier, "parcObject_CreateInstance returned NULL");
+
+ verifier->instance = parcObject_Acquire(instance);
+ verifier->interface = interfaceContext;
+
+ return verifier;
+}
+
+bool
+parcVerifier_VerifyDigestSignature(PARCVerifier *verifier, PARCKeyId *keyid, PARCCryptoHash *locallyComputedHash,
+ PARCCryptoSuite suite, PARCSignature *signatureToVerify)
+{
+ assertNotNull(verifier, "Parameter must be non-null PARCVerifier");
+ assertNotNull(locallyComputedHash, "cryptoHash to verify must not be null");
+ assertNotNull(signatureToVerify, "Signature to verify must not be null");
+
+ // null keyid is allowed now that we support CRCs, etc.
+
+ return verifier->interface->VerifyDigest(verifier->instance, keyid, locallyComputedHash, suite, signatureToVerify);
+}
+
+bool
+parcVerifier_AllowedCryptoSuite(PARCVerifier *verifier, PARCKeyId *keyid, PARCCryptoSuite suite)
+{
+ assertNotNull(verifier, "Parameter must be non-null PARCVerifier");
+ return verifier->interface->AllowedCryptoSuite(verifier->instance, keyid, suite);
+}
+
+PARCCryptoHasher*
+parcVerifier_GetCryptoHasher(PARCVerifier *verifier, PARCKeyId *keyid, PARCCryptoHashType hashType)
+{
+ assertNotNull(verifier, "Parameter must be non-null PARCVerifier");
+ return verifier->interface->GetCryptoHasher(verifier->instance, keyid, hashType);
+}
+
+void
+parcVerifier_AddKey(PARCVerifier *verifier, PARCKey *key)
+{
+ assertNotNull(verifier, "Parameter must be non-null PARCVerifier");
+ verifier->interface->AddKey(verifier->instance, key);
+}
+
+void
+parcVerifier_RemoveKeyId(PARCVerifier *verifier, PARCKeyId *keyid)
+{
+ assertNotNull(verifier, "Parameter must be non-null PARCVerifier");
+ verifier->interface->RemoveKeyId(verifier->instance, keyid);
+}
diff --git a/libparc/parc/security/parc_Verifier.h b/libparc/parc/security/parc_Verifier.h
new file mode 100644
index 00000000..09e3640f
--- /dev/null
+++ b/libparc/parc/security/parc_Verifier.h
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_Verifier.h
+ * @ingroup security
+ * @brief Structures and functions to support verification.
+ *
+ */
+#ifndef libparc_parc_Verifier_h
+#define libparc_parc_Verifier_h
+
+#include <parc/algol/parc_Object.h>
+
+#include <parc/security/parc_CryptoHasher.h>
+#include <parc/security/parc_Signature.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_Key.h>
+#include <parc/security/parc_CryptoSuite.h>
+
+struct parc_verifier;
+typedef struct parc_verifier PARCVerifier;
+
+/**
+ * @typedef PARCVerifierInterface
+ * @brief The interface for `PARCVerifier`
+ */
+typedef struct parc_verifier_interface {
+ /** @see parcVerifier_GetCryptoHasher */
+ PARCCryptoHasher *(*GetCryptoHasher)(PARCObject * interfaceContext, PARCKeyId * keyid, PARCCryptoHashType hashType);
+
+ /** @see parcVerifier_VerifyDigest */
+ bool (*VerifyDigest)(PARCObject *interfaceContext, PARCKeyId *keyid, PARCCryptoHash *locallyComputedHash,
+ PARCCryptoSuite suite, PARCSignature *signatureToVerify);
+
+ /** @see parcVerifier_AddKey */
+ void (*AddKey)(PARCObject *interfaceContext, PARCKey *key);
+
+ /** @see parcVerifier_RemoveKeyId */
+ void (*RemoveKeyId)(PARCObject *interfaceContext, PARCKeyId *keyid);
+
+ /** @see parcVerifier_AllowedCryptoSuite */
+ bool (*AllowedCryptoSuite)(PARCObject *interfaceContext, PARCKeyId *keyid, PARCCryptoSuite suite);
+} PARCVerifierInterface;
+
+/**
+ * Create a verifier context based on a concrete implementation.
+ *
+ * @param [in] instance A concrete implementation of a `PARCVerifier`
+ * @param [in] interfaceContext The interface of a concrete implementation of a `PARCVerifier`
+ *
+ * @return NULL A `PARCVerifier` could not be allocated
+ * @return PARCSigner A new `PARCVerifier` instance derived from the specified concrete signer context.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVerifier *verifier = parcVerifier_Create(verifierInstance, PARCInMemoryVerifierAsVerifier);
+ * }
+ * @endcode
+ */
+PARCVerifier *parcVerifier_Create(PARCObject *instance, PARCVerifierInterface *interfaceContext);
+
+/**
+ * Assert that an instance of `PARCVerifier` 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] verifier A pointer to a PARCVerifier instance.
+ *
+ * Example
+ * @code
+ * {
+ * PARCVerifier *verifier = parcVerifier_Create(verifierInstance, PARCInMemoryVerifierAsVerifier);
+ *
+ * parcVerifier_AssertValid(signer);
+ * }
+ * @endcode
+ */
+void parcVerifier_AssertValid(const PARCVerifier *verifier);
+
+/**
+ * Increase the number of references to the given `PARCVerifier` instance.
+ *
+ * A new instance is not created,
+ * only that the given instance's reference count is incremented.
+ * Discard the acquired reference by invoking `parcVerifier_Release()`.
+ *
+ * @param [in] signer A pointer to a `PARCVerifier` instance.
+ *
+ * @return NULL An error occurred.
+ * @return non-NULL A pointer to a PARCVerifier instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVerifier *verifier = parcVerifier_Create(verifierInstance, PARCInMemoryVerifierAsVerifier);
+ * PARCVerifier *handle = parcVerifier_Acquire(signer);
+ * // use the handle instance as needed
+ * }
+ * @endcode
+ */
+PARCVerifier *parcVerifier_Acquire(const PARCVerifier *verifier);
+
+/**
+ * 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.
+ *
+ * The contents of the dealloced memory used for the PARC object are undefined.
+ * Do not reference the object after the last release.
+ *
+ * @param [in,out] verifierPtr A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVerifier *verifier = parcVerifier_Create(verifierInstance, PARCInMemoryVerifierAsVerifier);
+ *
+ * parcVerifier_Release(&verifier);
+ * }
+ * @endcode
+ */
+void parcVerifier_Release(PARCVerifier **verifierPtr);
+
+/**
+ * Verify the signature against the provided digest with the specified key.
+ * If we do not trust the key, the signature will be rejected. In this context,
+ * trusting a key means that it was previously added to this verifiers "store".
+ *
+ * Returns true if the signature is accepted,false if it is rejected.
+ *
+ * @param [in] verifier A `PARCVerifier` instance.
+ * @param [in] keyId A `PARCKeyId` which identifies the verification key.
+ * @param [in] hashDigest A `PARCCryptoHash` which stores the locally computed digest.
+ * @param [in] suite The `PARCCryptoSuite` in which verification is performed.
+ * @param [in] signature The `PARCSignature` which is to be verified.
+ *
+ * @retval true If the signature is valid
+ * @retval false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVerifier *verifier = parcVerifier_Create(verifierInstance, PARCInMemoryVerifierAsVerifier);
+ *
+ * PARCKeyId *keyId = ...
+ * PARCCryptoHash *hash = ...
+ * PARCCryptoSuite suite = PARCCryptoSuite_RSA_SHA256;
+ * PARCSignature *signature = ...
+ *
+ * bool valid = parcVerifier_VerifyDigestSignature(verifier, keyId, hash, suite, signature);
+ * if (valid) {
+ * // proceed
+ * }
+ * }
+ * @endcode
+ */
+bool
+parcVerifier_VerifyDigestSignature(PARCVerifier *verifier, PARCKeyId *keyid, PARCCryptoHash *hashDigest,
+ PARCCryptoSuite suite, PARCSignature *signatureToVerify);
+
+/**
+ * Check to see if the specified `PARCKeyId` is allowed with the given `PARCCryptoSuite`.
+ *
+ * A`PARCKey` identified by the given `PARCKeyId` can only be used for a particular algorithm.
+ *
+ * @param [in] verifier A `PARCVerifier` instance with a store of trusted `PARCKey` instances.
+ * @param [in] keyId A `PARCKeyId` referring to the key we will check against (for this verifier).
+ * @param [in] suite A `PARCCryptoSuite` to check against.
+ *
+ * @retval true If allowed
+ * @retval false Otherwise
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVerifier *verifeir = ...
+ * PARCKeyId *keyId = ...
+ * bool isAllowed = parcVerifier_AllowedCryptoSuite(verifier, keyId, PARCCryptoSuite_RSA_SHA256);
+ * // act accordingly
+ * }
+ * @endcode
+ */
+bool parcVerifier_AllowedCryptoSuite(PARCVerifier *verifier, PARCKeyId *keyId, PARCCryptoSuite suite);
+
+/**
+ * Returns a `PARCCryptoHasher` for use with the `PARCKeyId`. The caller should have already
+ * verified that the specified `PARCCryptoHashType` is compatible with the key ID by
+ * checking the AllowedCryptoSuite.
+ *
+ * @param [in] verifier A `PARCVerifier` instance with a store of trusted `PARCKey` instances.
+ * @param [in] keyId A `PARCKeyId` referring to the key we will check against (for this verifier).
+ * @param [in] suite A `PARCCryptoSuite` to check against.
+ *
+ * @retval non-NULL A `PARCCryptoHasher` instance.
+ * @retval NULL If the PARCCryptoHashType is not compatible with the key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVerifier *verifeir = ...
+ * PARCKeyId *keyId = ...
+ * bool isAllowed = parcVerifier_AllowedCryptoSuite(verifier, keyId, PARCCryptoHashType_SHA256);
+ * // act accordingly
+ * }
+ * @endcode
+ */
+PARCCryptoHasher *parcVerifier_GetCryptoHasher(PARCVerifier *verifier, PARCKeyId *keyid, PARCCryptoHashType hashType);
+
+/**
+ * Add the specified `PARCKey` to the trusted key store.
+ *
+ * @param [in] verifier A `PARCVerifier` instance with a store of trusted `PARCKey` instances.
+ * @param [in] key A `PARCKey` containing the new trusted key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVerifier *verifeir = ...
+ * PARCKey *key = ...
+ * parcVerifier_AddKey(verifier, key);
+ * }
+ * @endcode
+ */
+void parcVerifier_AddKey(PARCVerifier *verifier, PARCKey *key);
+
+/**
+ * Remove the key associated with the given `PARCKeyId` from the trusted key store.
+ *
+ * @param [in] verifier A `PARCVerifier` instance with a store of trusted `PARCKey` instances.
+ * @param [in] keyId A `PARCKeyId` referencing the `PARCKey` to remove from the keystore.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCVerifier *verifeir = ...
+ * PARCKey *key = ...
+ * parcVerifier_AddKey(verifier, key);
+ *
+ * // Use the verifier with the key...
+ * ...
+ *
+ * // Now remove it because we no longer need or trust it.
+ * PARCKeyId *keyId = parcKey_GetKeyId(key);
+ * parcVerifier_RemoveKeyId(verifier, keyId);
+ * }
+ * @endcode
+ */
+void parcVerifier_RemoveKeyId(PARCVerifier *verifier, PARCKeyId *keyid);
+#endif // libparc_parc_Verifier_h
diff --git a/libparc/parc/security/parc_X509Certificate.c b/libparc/parc/security/parc_X509Certificate.c
new file mode 100644
index 00000000..67ee6b2b
--- /dev/null
+++ b/libparc/parc/security/parc_X509Certificate.c
@@ -0,0 +1,645 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * parc_X509Certificate.c
+ * PARC Library
+ */
+
+#include <config.h>
+
+#include <parc/security/parc_X509Certificate.h>
+#include <parc/security/parc_Certificate.h>
+
+#include <parc/security/parc_CryptoHash.h>
+#include <parc/security/parc_Security.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/security/parc_KeyType.h>
+
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+#include <openssl/rand.h>
+#include <openssl/pkcs12.h>
+
+static PARCCryptoHash *_getPublicKeyDigest(void *interfaceContext);
+static PARCCryptoHash *_getCertificateDigest(void *interfaceContext);
+static PARCBuffer *_getDEREncodedCertificate(void *interfaceContext);
+static PARCBuffer *_getDEREncodedPublicKey(void *interfaceContext);
+static PARCCertificateType _getCertificateType(const void *cert);
+static PARCContainerEncoding _getContainerEncoding(const void *cert);
+
+PARCCertificateInterface *PARCX509CertificateInterface = &(PARCCertificateInterface) {
+ .GetPublicKeyDigest = _getPublicKeyDigest,
+ .GetCertificateDigest = _getCertificateDigest,
+ .GetDEREncodedCertificate = _getDEREncodedCertificate,
+ .GetDEREncodedPublicKey = _getDEREncodedPublicKey,
+ .GetCertificateType = _getCertificateType,
+ .GetContainerEncoding = _getContainerEncoding
+};
+
+struct parc_X509_certificate {
+ PARCCertificateType type;
+ PARCContainerEncoding encoding;
+
+ // Cache of results
+ PARCCryptoHash *keyDigest;
+ PARCCryptoHash *certificateDigest;
+ PARCBuffer *derEncodedCertificate;
+ PARCBuffer *derEncodedKey;
+
+ BIO *certificateBIO;
+ X509 *certificate;
+ EVP_PKEY *publicKey;
+};
+
+#ifdef __APPLE__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+static PARCCryptoHash *
+_getPublicKeyDigest(void *interfaceContext)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(interfaceContext, "Parameter must be non-null PARCX509Certificate");
+
+ PARCX509Certificate *certificate = (PARCX509Certificate *) interfaceContext;
+
+ if (certificate->keyDigest == NULL) {
+ PARCBuffer *derEncodedKey = _getDEREncodedPublicKey(certificate);
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBuffer(hasher, derEncodedKey);
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+
+ certificate->keyDigest = parcCryptoHash_Create(PARCCryptoHashType_SHA256, parcCryptoHash_GetDigest(hash));
+ parcCryptoHash_Release(&hash);
+ parcCryptoHasher_Release(&hasher);
+ }
+
+ return certificate->keyDigest;
+}
+
+static PARCCryptoHash *
+_getCertificateDigest(void *interfaceContext)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(interfaceContext, "Parameter must be non-null PARCX509Certificate");
+
+ PARCX509Certificate *certificate = (PARCX509Certificate *) interfaceContext;
+
+ if (certificate->certificateDigest == NULL) {
+ uint8_t digestBuffer[SHA256_DIGEST_LENGTH];
+ int result = X509_digest(certificate->certificate, EVP_sha256(), digestBuffer, NULL);
+ if (result) {
+ PARCBuffer *digest =
+ parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH, digestBuffer));
+ certificate->certificateDigest = parcCryptoHash_Create(PARCCryptoHashType_SHA256, digest);
+ parcBuffer_Release(&digest);
+ }
+ }
+
+ return certificate->certificateDigest;
+}
+
+static PARCBuffer *
+_getDEREncodedCertificate(void *interfaceContext)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(interfaceContext, "Parameter must be non-null PARCX509Certificate");
+
+ PARCX509Certificate *certificate = (PARCX509Certificate *) interfaceContext;
+
+ if (certificate->derEncodedCertificate == NULL) {
+ uint8_t *der = NULL;
+
+ // this allocates memory for der
+ int derLength = i2d_X509(certificate->certificate, &der);
+ if (derLength > 0) {
+ certificate->derEncodedCertificate =
+ parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(derLength), derLength, der));
+ }
+ OPENSSL_free(der);
+ }
+
+ return certificate->derEncodedCertificate;
+}
+
+static PARCBuffer *
+_getDEREncodedPublicKey(void *interfaceContext)
+{
+ parcSecurity_AssertIsInitialized();
+
+ assertNotNull(interfaceContext, "Parameter must be non-null PARCX509Certificate");
+
+ PARCX509Certificate *certificate = (PARCX509Certificate *) interfaceContext;
+
+ if (certificate->derEncodedKey == NULL) {
+ uint8_t *der = NULL;
+
+ // this allocates memory for der
+ int derLength = i2d_PUBKEY(certificate->publicKey, &der);
+ if (derLength > 0) {
+ certificate->derEncodedKey = parcBuffer_Flip(parcBuffer_PutArray(parcBuffer_Allocate(derLength), derLength, der));
+ }
+ OPENSSL_free(der);
+ }
+
+ return certificate->derEncodedKey;
+}
+
+static PARCCertificateType
+_getCertificateType(const void *instance)
+{
+ PARCX509Certificate *certificate = (PARCX509Certificate *) instance;
+ return certificate->type;
+}
+
+static PARCContainerEncoding
+_getContainerEncoding(const void *instance)
+{
+ PARCX509Certificate *certificate = (PARCX509Certificate *) instance;
+ return certificate->encoding;
+}
+
+static void
+_parcX509Certificate_FinalRelease(PARCX509Certificate **certP)
+{
+ PARCX509Certificate *cert = (PARCX509Certificate *) *certP;
+ if (cert->certificateBIO != NULL) {
+ BIO_free_all(cert->certificateBIO);
+ }
+ if (cert->publicKey != NULL) {
+ EVP_PKEY_free(cert->publicKey);
+ }
+ if (cert->certificate != NULL) {
+ X509_free(cert->certificate);
+ }
+ if (cert->keyDigest != NULL) {
+ parcCryptoHash_Release(&cert->keyDigest);
+ }
+ if (cert->certificateDigest != NULL) {
+ parcCryptoHash_Release(&cert->certificateDigest);
+ }
+ if (cert->derEncodedCertificate != NULL) {
+ parcBuffer_Release(&cert->derEncodedCertificate);
+ }
+ if (cert->derEncodedKey != NULL) {
+ parcBuffer_Release(&cert->derEncodedKey);
+ }
+}
+
+parcObject_ExtendPARCObject(PARCX509Certificate, _parcX509Certificate_FinalRelease, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static PARCX509Certificate *
+_createEmptyCertificate()
+{
+ PARCX509Certificate *cert = parcObject_CreateInstance(PARCX509Certificate);
+ cert->certificateBIO = NULL;
+ cert->certificate = NULL;
+ cert->publicKey = NULL;
+ cert->keyDigest = NULL;
+ cert->certificateDigest = NULL;
+ cert->derEncodedCertificate = NULL;
+ cert->derEncodedKey = NULL;
+ assertNotNull(cert, "Failure allocating memory for a new PARCX509Certificate instance");
+
+ return cert;
+}
+
+static bool
+_addCertificateExtensionWithContext(X509 *cert, int nid, char *value)
+{
+ X509_EXTENSION *extension;
+ X509V3_CTX context;
+
+ X509V3_set_ctx_nodb(&context);
+ X509V3_set_ctx(&context, cert, cert, NULL, NULL, 0);
+ extension = X509V3_EXT_conf_nid(NULL, &context, nid, value);
+ if (extension == NULL) {
+ return false;
+ }
+ X509_add_ext(cert, extension, -1);
+ X509_EXTENSION_free(extension);
+ return true;
+}
+
+static bool
+_addCertificateExtension(X509 *cert, int nid, char *value)
+{
+ X509_EXTENSION *extension = X509V3_EXT_conf_nid(NULL, NULL, nid, value);
+ if (extension == NULL) {
+ return false;
+ }
+ X509_add_ext(cert, extension, -1);
+ X509_EXTENSION_free(extension);
+ return true;
+}
+
+static bool
+_addKeyIdentifier(X509 *cert)
+{
+ unsigned char spkid[SHA256_DIGEST_LENGTH];
+ char spkid_hex[1 + 2 * SHA256_DIGEST_LENGTH];
+
+ /* Generate a KeyID which is the SHA256 digest of the DER encoding
+ * of a SubjectPublicKeyInfo. Note that this is slightly uncommon,
+ * but it is more general and complete than digesting the BIT STRING
+ * component of the SubjectPublicKeyInfo itself (and no standard dictates
+ * how you must generate a key ID). This code must produce the same result
+ * as the Java version applied to the same SubjectPublicKeyInfo.
+ */
+
+ if (ASN1_item_digest(ASN1_ITEM_rptr(X509_PUBKEY), EVP_sha256(), X509_get_X509_PUBKEY(cert), spkid, NULL)) {
+ for (int i = 0; i < 32; i++) {
+ snprintf(&spkid_hex[2 * i], 3, "%02X", (unsigned) spkid[i]);
+ }
+ if (_addCertificateExtension(cert, NID_subject_key_identifier, spkid_hex) == true) {
+ if (_addCertificateExtensionWithContext(cert, NID_authority_key_identifier, "keyid:always") == true) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static bool
+_addSubjectName(X509 *cert, const char *subjectname)
+{
+ // Set up the simple subject name and issuer name for the certificate.
+ X509_NAME *name = X509_get_subject_name(cert);
+ assertNotNull(name, "Got null name from X509_get_subject_name");
+
+ if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *) subjectname, -1, -1, 0)) {
+ if (X509_set_issuer_name(cert, name)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool
+_addRandomSerial(X509 *cert)
+{
+ unsigned long serial = 0;
+ unsigned char serial_bytes[sizeof(serial)];
+
+ // Construct random positive serial number.
+ RAND_bytes(serial_bytes, sizeof(serial_bytes));
+ serial_bytes[0] &= 0x7F;
+ serial = 0;
+ for (int i = 0; i < sizeof(serial_bytes); i++) {
+ serial = (256 * serial) + serial_bytes[i];
+ }
+ ASN1_INTEGER_set(X509_get_serialNumber(cert), serial);
+ return true;
+}
+
+static bool
+_addValidityPeriod(X509 *cert, size_t validityDays)
+{
+ // Set the validity from now for the specified number of days.
+ X509_gmtime_adj(X509_get_notBefore(cert), (long) 0);
+ X509_gmtime_adj(X509_get_notAfter(cert), (long) (60 * 60 * 24 * validityDays));
+ return true;
+}
+
+static bool
+_addExtensions(X509 *cert)
+{
+ // Add the necessary extensions.
+ if (_addCertificateExtension(cert, NID_basic_constraints, "critical,CA:FALSE") == true) {
+ if (_addCertificateExtension(cert, NID_key_usage, "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement") == true) {
+ if (_addCertificateExtension(cert, NID_ext_key_usage, "clientAuth") == true) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static PARCX509Certificate *
+_parcX509Certificate_CreateFromPEMFile(const char *filename)
+{
+ parcSecurity_AssertIsInitialized();
+
+ PARCX509Certificate *cert = _createEmptyCertificate();
+
+ FILE *fp = fopen(filename, "rb");
+ if (fp == NULL) {
+ parcX509Certificate_Release(&cert);
+ return NULL;
+ }
+
+ cert->certificateBIO = BIO_new(BIO_s_file());
+ size_t result = BIO_read_filename(cert->certificateBIO, filename);
+ assertTrue(result == 1, "Unable to open the specified file");
+
+ cert->certificate = PEM_read_bio_X509(cert->certificateBIO, NULL, 0, NULL);
+ cert->publicKey = X509_get_pubkey(cert->certificate);
+
+ return cert;
+}
+
+parcObject_ImplementAcquire(parcX509Certificate, PARCX509Certificate);
+
+parcObject_ImplementRelease(parcX509Certificate, PARCX509Certificate);
+
+PARCX509Certificate *
+parcX509Certificate_CreateFromPEMFile(const char *filename)
+{
+ PARCX509Certificate *certificate = _parcX509Certificate_CreateFromPEMFile(filename);
+ if (certificate) {
+ certificate->type = PARCCertificateType_X509;
+ certificate->encoding = PARCContainerEncoding_PEM;
+ return certificate;
+ }
+ return NULL;
+}
+
+PARCX509Certificate *
+parcX509Certificate_CreateFromDERBuffer(const PARCBuffer *buffer)
+{
+ parcSecurity_AssertIsInitialized();
+
+ PARCX509Certificate *cert = _createEmptyCertificate();
+ cert->type = PARCCertificateType_X509;
+ cert->encoding = PARCContainerEncoding_DER;
+
+ PARCByteArray *array = parcBuffer_Array(buffer);
+ uint8_t *arrayIn = parcByteArray_Array(array);
+
+ cert->certificate = d2i_X509(&cert->certificate, (const unsigned char **) &arrayIn, parcBuffer_Remaining(buffer));
+ if (cert->certificate == NULL) {
+ parcX509Certificate_Release(&cert);
+ return NULL;
+ }
+ cert->publicKey = X509_get_pubkey(cert->certificate);
+
+ return cert;
+}
+
+PARCX509Certificate * _createSelfSignedCertificate_RSA(PARCBuffer **privateKeyBuffer, char *subjectName, int keyLength, size_t validityDays)
+{
+ parcSecurity_AssertIsInitialized();
+
+ RSA *rsa = RSA_new();
+ assertNotNull(rsa, "RSA_new failed.");
+
+ EVP_PKEY *privateKey = EVP_PKEY_new();
+ assertNotNull(privateKey, "EVP_PKEY_new() failed.");
+
+ X509 *cert = X509_new();
+ assertNotNull(cert, "X509_new() failed.");
+
+ int res;
+ BIGNUM *pub_exp;
+
+ pub_exp = BN_new();
+
+ BN_set_word(pub_exp, RSA_F4);
+ res = 1;
+ bool result = false;
+ if (RSA_generate_key_ex(rsa, keyLength, pub_exp, NULL)) {
+ if (EVP_PKEY_set1_RSA(privateKey, rsa)) {
+ if (X509_set_version(cert, 2)) { // 2 => X509v3
+ result = true;
+ }
+ }
+ }
+ if (result) {
+ // add serial number
+ if (_addRandomSerial(cert) == true) {
+ if (_addValidityPeriod(cert, validityDays) == true) {
+ if (X509_set_pubkey(cert, privateKey) == 1) {
+ if (_addSubjectName(cert, subjectName) == true) {
+ if (_addExtensions(cert) == true) {
+ if (_addKeyIdentifier(cert) == true) {
+ // The certificate is complete, sign it.
+ if (X509_sign(cert, privateKey, EVP_sha256())) {
+ result = true;
+ } else {
+ printf("error: (%d) %s\n", res, ERR_lib_error_string(res));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ERR_print_errors_fp(stdout);
+
+ BN_free(pub_exp);
+
+ uint8_t *certificateDerEncoding = NULL;
+ int numBytes = i2d_X509(cert, &certificateDerEncoding);
+ if (numBytes < 0) {
+ EVP_PKEY_free(privateKey);
+ RSA_free(rsa);
+ X509_free(cert);
+
+ return NULL;
+ }
+
+ PARCBuffer *derBuffer = parcBuffer_Allocate(numBytes);
+ parcBuffer_Flip(parcBuffer_PutArray(derBuffer, numBytes, certificateDerEncoding));
+
+ PARCX509Certificate *certificate = parcX509Certificate_CreateFromDERBuffer(derBuffer);
+ parcBuffer_Release(&derBuffer);
+
+ uint8_t *privateKeyBytes = NULL;
+ int privateKeyByteCount = i2d_PrivateKey(privateKey, &privateKeyBytes);
+ if (privateKeyByteCount < 0) {
+ EVP_PKEY_free(privateKey);
+ RSA_free(rsa);
+ X509_free(cert);
+
+ return NULL;
+ }
+
+ *privateKeyBuffer = parcBuffer_Allocate(privateKeyByteCount);
+ parcBuffer_Flip(parcBuffer_PutArray(*privateKeyBuffer, privateKeyByteCount, privateKeyBytes));
+
+ EVP_PKEY_free(privateKey);
+ RSA_free(rsa);
+ X509_free(cert);
+
+ return certificate;
+}
+
+static inline int _get_EC_params_from_lenght(int keyLength)
+{
+ //For the moment only support 256bit key length
+ switch (keyLength)
+ {
+ case 160:
+ return NID_secp160k1;
+ case 192:
+ return NID_secp192k1;
+ case 224:
+ return NID_secp224k1;
+ case 256:
+ return NID_secp256k1;
+ default:
+ return -1;
+ }
+
+}
+
+PARCX509Certificate * _createSelfSignedCertificate_EC(PARCBuffer **privateKeyBuffer, char *subjectName, int keyLength, size_t validityDays)
+{
+ parcSecurity_AssertIsInitialized();
+ int curve_params = _get_EC_params_from_lenght(keyLength);
+ bool result = false;
+
+ if (curve_params == -1)
+ return NULL;
+
+ EC_KEY *ec_key = EC_KEY_new_by_curve_name(curve_params);
+ assertNotNull(ec_key, "EC key creation failed.");
+
+ EC_KEY_set_asn1_flag(ec_key, OPENSSL_EC_NAMED_CURVE);
+
+ EVP_PKEY *pkey = EVP_PKEY_new();
+ assertNotNull(pkey, "EVP_PKEY_new() failed.");
+
+ X509 *cert = X509_new();
+ assertNotNull(cert, "X509_new() failed.");
+
+ int res;
+
+
+ if((res = (EC_KEY_generate_key(ec_key))) < 0 )
+ printf("error: (%d) %s\n", res, ERR_lib_error_string(res));
+ else if((res = (EVP_PKEY_set1_EC_KEY(pkey, ec_key))) < 0 )
+ printf("error: (%d) %s\n", res, ERR_lib_error_string(res));
+ else if (X509_set_version(cert, 2)) { // 2 => X509v3
+ result = true;
+ }
+
+ if (result) {
+ // add serial number
+ if (_addRandomSerial(cert) == true) {
+ if (_addValidityPeriod(cert, validityDays) == true) {
+ if (X509_set_pubkey(cert, pkey) == 1) {
+ if (_addSubjectName(cert, subjectName) == true) {
+ if (_addExtensions(cert) == true) {
+ if (_addKeyIdentifier(cert) == true) {
+ // The certificate is complete, sign it.
+ if (X509_sign(cert, pkey, EVP_sha256())) {
+ result = true;
+ } else {
+ printf("error: (%d) %s\n", res, ERR_lib_error_string(res));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ERR_print_errors_fp(stdout);
+
+
+
+ uint8_t *certificateDerEncoding = NULL;
+ int numBytes = i2d_X509(cert, &certificateDerEncoding);
+ if (numBytes < 0) {
+ EVP_PKEY_free(pkey);
+ EC_KEY_free(ec_key);
+ X509_free(cert);
+
+ return NULL;
+ }
+
+ PARCBuffer *derBuffer = parcBuffer_Allocate(numBytes);
+ parcBuffer_Flip(parcBuffer_PutArray(derBuffer, numBytes, certificateDerEncoding));
+
+ PARCX509Certificate *certificate = parcX509Certificate_CreateFromDERBuffer(derBuffer);
+ parcBuffer_Release(&derBuffer);
+
+ uint8_t *pkeyBytes = NULL;
+ int pkeyByteCount = i2d_PrivateKey(pkey, &pkeyBytes);
+ if (pkeyByteCount < 0) {
+ EVP_PKEY_free(pkey);
+ EC_KEY_free(ec_key);
+ X509_free(cert);
+
+ return NULL;
+ }
+
+ *privateKeyBuffer = parcBuffer_Allocate(pkeyByteCount);
+ parcBuffer_Flip(parcBuffer_PutArray(*privateKeyBuffer, pkeyByteCount, pkeyBytes));
+
+ EVP_PKEY_free(pkey);
+ EC_KEY_free(ec_key);
+ X509_free(cert);
+
+ return certificate;
+}
+
+PARCX509Certificate *
+parcX509Certificate_CreateSelfSignedCertificate(PARCBuffer **privateKeyBuffer, char *subjectName, int keyLength, size_t validityDays, PARCKeyType keyType)
+{
+ switch(keyType) {
+ case PARCKeyType_RSA:
+ return _createSelfSignedCertificate_RSA(privateKeyBuffer, subjectName, keyLength, validityDays);
+ case PARCKeyType_EC:
+ return _createSelfSignedCertificate_EC(privateKeyBuffer, subjectName, keyLength, validityDays);
+ }
+
+ return NULL;
+}
+
+
+PARCCryptoHash *
+parcX509Certificate_GetCertificateDigest(PARCX509Certificate *certificate)
+{
+ return _getCertificateDigest(certificate);
+}
+
+PARCCryptoHash *
+parcX509Certificate_getPublicKeyDigest(PARCX509Certificate *certificate)
+{
+ return _getPublicKeyDigest(certificate);
+}
+
+PARCBuffer *
+parcX509Certificate_GetDEREncodedCertificate(PARCX509Certificate *certificate)
+{
+ return _getDEREncodedCertificate(certificate);
+}
+
+PARCBuffer *
+parcX509Certificate_GetDEREncodedPublicKey(PARCX509Certificate *certificate)
+{
+ return _getDEREncodedPublicKey(certificate);
+}
+
+#ifdef __APPLE__
+#pragma clang diagnostic pop
+#endif
+
diff --git a/libparc/parc/security/parc_X509Certificate.h b/libparc/parc/security/parc_X509Certificate.h
new file mode 100755
index 00000000..c6ca8247
--- /dev/null
+++ b/libparc/parc/security/parc_X509Certificate.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_X509Certificate.h
+ * @ingroup security
+ * @brief The API for a generic certificate.
+ *
+ */
+
+#ifndef libparc_parc_X509Certificate_h
+#define libparc_parc_X509Certificate_h
+
+#include <parc/security/parc_Certificate.h>
+#include <parc/security/parc_KeyType.h>
+
+struct parc_X509_certificate;
+typedef struct parc_X509_certificate PARCX509Certificate;
+
+extern PARCCertificateInterface *PARCX509CertificateInterface;
+
+/**
+ * Create a `PARCX509Certificate` from a PEM-encoded file.
+ *
+ * @param [in] filename A nul-terminated path to a certificate file.
+ *
+ * @return NULL The memory could not be allocated.
+ * @return non-NULL A newly allocated `PARCX509Certificate`.
+ *
+ * Example:
+ * @code
+ * {
+ * char *pathToCertificate = "file.pem";
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(pathToCertificate);
+ * }
+ * @endcode
+ */
+PARCX509Certificate *parcX509Certificate_CreateFromPEMFile(const char *filename);
+
+/**
+ * Create a `PARCX509Certificate` from a DER-encoded buffer.
+ *
+ * @param [in] buffer A `PARCBuffer` instance containing the DER-encoded certificate.
+ *
+ * @return NULL The memory could not be allocated.
+ * @return non-NULL A newly allocated `PARCX509Certificate`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBuffer *certificateBuffer = ...
+ * PARCX509Certificate *certificate = parcX509Certificate_CreateFromDERBuffer(certificateBuffer);
+ * }
+ * @endcode
+ */
+PARCX509Certificate *parcX509Certificate_CreateFromDERBuffer(const PARCBuffer *buffer);
+
+// TODO
+PARCX509Certificate *parcX509Certificate_CreateSelfSignedCertificate(PARCBuffer **privateKey, char *subjectName, int keyLength, size_t valdityDays, PARCKeyType ketType);
+
+/**
+ * Increase the number of references to a `PARCX509Certificate` instance.
+ *
+ * Note that a new `PARCX509Certificate` is not created,
+ * only that the given `PARCX509Certificate` reference count is incremented.
+ * Discard the reference by invoking {@link parcX509Certificate_Release}.
+ *
+ * @param [in] certificate A pointer to the original instance.
+ * @return The value of the input parameter @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *x = parcX509Certificate_CreateFromPEMFile(...);
+ * PARCX509Certificate *x2 = parcX509Certificate_Acquire(x);
+ *
+ * parcX509Certificate_Release(&x);
+ * parcX509Certificate_Release(&x2);
+ * }
+ * @endcode
+ *
+ * @see {@link parcX509Certificate_Release}
+ */
+PARCX509Certificate *parcX509Certificate_Acquire(const PARCX509Certificate *certificate);
+
+/**
+ * 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] certificateP A pointer to a pointer to the instance to release.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *x = parcX509Certificate_CreateFromPEMFile(...);
+ *
+ * parcX509Certificate_Release(&x);
+ * }
+ * @endcode
+ */
+void parcX509Certificate_Release(PARCX509Certificate **certificateP);
+
+/**
+ * Retrieve the SHA-256 digest of the DER-encoded certificate.
+ *
+ * @param [in] certificate A pointer to `PARCX509Certificate` instance.
+ *
+ * @return The SHA-256 digest of the @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *x = parcX509Certificate_CreateFromPEMFile(...);
+ *
+ * PARCCryptoHash *digest = parcX509Certificate_GetCertificateDigest(x);
+ * // use the digest
+ *
+ * parcX509Certificate_Release(&x);
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcX509Certificate_GetCertificateDigest(PARCX509Certificate *certificate);
+
+/**
+ * Retrieve the SHA-256 digest of the DER-encoded public key that
+ * is contained in the specified `PARCX509Certificate`.
+ *
+ * @param [in] certificate A pointer to `PARCX509Certificate` instance.
+ *
+ * @return The SHA-256 digest of the @p instance's public key.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *x = parcX509Certificate_CreateFromPEMFile(...);
+ *
+ * PARCCryptoHash *digest = parcX509Certificate_GetCertificateKeyDigest(x);
+ * // use the digest
+ *
+ * parcX509Certificate_Release(&x);
+ * }
+ * @endcode
+ */
+PARCCryptoHash *parcX509Certificate_GetCertificateKeyDigest(PARCX509Certificate *certificate);
+
+/**
+ * Retrieve the DER-encoded representation of the specified `PARCX509Certificate`.
+ *
+ * @param [in] certificate A pointer to `PARCX509Certificate` instance.
+ *
+ * @return A newly allocated `PARCBuffer` instance containing the DER-encoded form
+ * of the specified `PARCX509Certificate`.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *x = parcX509Certificate_CreateFromPEMFile(...);
+ *
+ * PARCBuffer *certificateDER = parcX509Certificate_GetDEREncodedCertificate(x);
+ * // use the digest
+ *
+ * parcX509Certificate_Release(&x);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcX509Certificate_GetDEREncodedCertificate(PARCX509Certificate *certificate);
+
+/**
+ * Retrieve the DER-encoded representation of the public key contained within
+ * the specified `PARCX509Certificate`.
+ *
+ * @param [in] certificate A pointer to `PARCX509Certificate` instance.
+ *
+ * @return A newly allocated `PARCBuffer` instance containing the DER-encoded form
+ * of the public key in the `PARCX509Certificate` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCX509Certificate *x = parcX509Certificate_CreateFromPEMFile(...);
+ *
+ * PARCBuffer *publicKeyDER = parcX509Certificate_GetDEREncodedPublicKey(x);
+ * // use the digest
+ *
+ * parcX509Certificate_Release(&x);
+ * }
+ * @endcode
+ */
+PARCBuffer *parcX509Certificate_GetDEREncodedPublicKey(PARCX509Certificate *certificate);
+#endif // libparc_parc_X509Certificate_h
diff --git a/libparc/parc/security/test/.gitignore b/libparc/parc/security/test/.gitignore
new file mode 100644
index 00000000..bda8c802
--- /dev/null
+++ b/libparc/parc/security/test/.gitignore
@@ -0,0 +1,24 @@
+test_parc_AesSignerFileStore
+test_parc_CryptoCache
+test_parc_InMemoryVerifier
+test_parc_KeyId
+test_parc_PublicKeySignerPkcs12Store
+test_parc_SelfSignedCertificate
+test_parc_Signature
+test_parc_Signer
+test_parc_SymmetricSignerFileStore
+test_parc_Security
+test_parc_CryptoHash
+test_parc_CryptoHashType
+test_parc_CryptoSuite
+test_parc_Identity
+test_parc_IdentityFile
+test_parc_Key
+test_parc_KeyStore
+test_parc_Verifier
+test_parc_SigningAlgorithm
+test_parc_Certificate
+test_parc_CertificateFactory
+test_parc_ContainerEncoding
+test_parc_CertificateType
+test_parc_X509Certificate
diff --git a/libparc/parc/security/test/CMakeLists.txt b/libparc/parc/security/test/CMakeLists.txt
new file mode 100644
index 00000000..40a5eb70
--- /dev/null
+++ b/libparc/parc/security/test/CMakeLists.txt
@@ -0,0 +1,88 @@
+set(TestsExpectedToPass
+ test_parc_Certificate
+ test_parc_CertificateFactory
+ test_parc_CertificateType
+ test_parc_ContainerEncoding
+ test_parc_CryptoCache
+ test_parc_CryptoHash
+ test_parc_CryptoHashType
+ test_parc_CryptoHasher
+ test_parc_CryptoSuite
+ test_parc_DiffieHellman
+ test_parc_DiffieHellmanKeyShare
+ test_parc_Identity
+ test_parc_IdentityFile
+ test_parc_InMemoryVerifier
+ test_parc_InMemoryVerifierECDSA
+ test_parc_Key
+ test_parc_KeyId
+ test_parc_KeyStore
+ test_parc_SecureRandom
+ test_parc_Pkcs12KeyStore
+ test_parc_Pkcs12KeyStoreECDSA
+ test_parc_PublicKeySigner
+ test_parc_PublicKeyECSigner
+ test_parc_SymmetricKeySigner
+ test_parc_SymmetricKeyStore
+ test_parc_Security
+ test_parc_Signature
+ test_parc_Signer
+ test_parc_SignerEC
+ test_parc_SigningAlgorithm
+ test_parc_Verifier
+ test_parc_X509Certificate
+ )
+
+set(EXTRA_DATA_FILES
+ README.digests
+ README.keystore
+ README.symmetric
+ test_crt.der
+ test_crt_der.bin
+ test_crt_sha256.bin
+ test_der.bin
+ test_digest_bytes_128.bin
+ test_digest_bytes_128.sha256
+ test_digest_bytes_128.sha512
+ test.pem
+ test_pubkey.bin
+ test_pubkey.der
+ test_pubkey.pem
+ test_random_bytes
+ test_random_bytes.sig
+ test_random_bytes.sig_ec
+ test_random_bytes.hmac_sha256
+ test_random_bytes.hmac_sha512
+ test_rsa.p12
+ test_rsa_crt.der
+ test_rsa_crt_sha256.bin
+ test_rsa_key.der
+ test_rsa_key.pem
+ test_rsa_pub.der
+ test_rsa_pub.pem
+ test_rsa_pub_sha256.bin
+ test_symmetric_key.bin
+ test_symmetric_key.sha256
+ test_ec.p12
+ test_ec_crt.der
+ test_ec_crt_sha256.bin
+ test_ec_key.der
+ test_ec_key.pem
+ test_ec_pub.der
+ test_ec_pub.pem
+ test_ec_pub_sha256.bin
+ )
+
+foreach(data_file ${EXTRA_DATA_FILES})
+ configure_file(${data_file} ${data_file} COPYONLY)
+endforeach()
+
+
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
diff --git a/libparc/parc/security/test/README.digests b/libparc/parc/security/test/README.digests
new file mode 100644
index 00000000..4abfa940
--- /dev/null
+++ b/libparc/parc/security/test/README.digests
@@ -0,0 +1,12 @@
+#
+# Generate some blocks of bytes to digest, then calculate the "truth" via openssl
+
+dd if=/dev/urandom of=test_digest_bytes_128.bin bs=128 count=1
+
+openssl dgst -sha256 -binary < test_digest_bytes_128.bin > test_digest_bytes_128.sha256
+openssl dgst -sha512 -binary < test_digest_bytes_128.bin > test_digest_bytes_128.sha512
+
+# these are for the symmetric key tests
+openssl sha256 -hmac 'apple_pie_is_good' -binary < test_random_bytes > test_random_bytes.hmac_sha256
+openssl sha512 -hmac 'apple_pie_is_good' -binary < test_random_bytes > test_random_bytes.hmac_sha512
+
diff --git a/libparc/parc/security/test/README.keystore b/libparc/parc/security/test/README.keystore
new file mode 100644
index 00000000..0c9c3a58
--- /dev/null
+++ b/libparc/parc/security/test/README.keystore
@@ -0,0 +1,63 @@
+
+# This set of commands creates an RSA public/private key pair,
+# self-signs it, then puts it all in a pkcs12 container with
+# the password "blueberry"
+#
+# We use these files in the test_ccnx_FileKeystore tests.
+
+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
+
+# saves the public key in DER form so we can calculate the sha256 of it
+openssl rsa -in test_rsa_key.pem -outform DER -pubout -out test_rsa_pub.der
+
+# save the private key in DER form so we can compare in code
+openssl rsa -in test_rsa_key.pem -outform DER -out test_rsa_key.der
+
+# computes the sha256 and saves it in binary form
+openssl sha256 -out test_rsa_pub_sha256.bin -sha256 -binary < test_rsa_pub.der
+
+# Save the certificate in DER form, then get the SHA256 hash of it
+# These are similar to doing "openssl x509 -in test_rsa.crt -fingerprint -sha256"
+openssl x509 -outform DER -out test_rsa_crt.der -in test_rsa.crt
+openssl sha256 -out test_rsa_crt_sha256.bin -sha256 -binary < test_rsa_crt.der
+
+# To verify signing, we create a random buffer, then sign with a SHA256 digest
+
+dd if=/dev/urandom of=test_random_bytes bs=512 count=1
+openssl sha -sha256 -sign test_rsa_key.pem -out test_random_bytes.sig < test_random_bytes
+
+# the "-in test_rsa_pub_sha256.bin" is the binary digest we will sign.
+openssl rsautl -sign -inkey test_rsa_key.pem -in test_rsa_pub_sha256.bin -out test_rsa_pub_sha256.bin.sig
+
+
+#EC
+openssl ecparam -name secp256k1 -genkey -noout -out test_ec_key.pem
+openssl ec -pubout -in test_ec_key.pem -out test_ec_pub.pem
+openssl req -new -key test_ec_key.pem -out test_ec.csr
+openssl x509 -req -days 365 -in test_ec.csr -signkey test_ec_key.pem -out test_ec.crt
+openssl pkcs12 -export -in test_ec.crt -inkey test_ec_key.pem -out test_ec.p12 -name ccnxuser -CAfile test_ec.crt -caname root -chain -passout pass:blueberry
+
+# saves the public key in DER form so we can calculate the sha256 of it
+openssl ec -in test_ec_key.pem -outform DER -pubout -out test_ec_pub.der
+
+# save the private key in DER form so we can compare in code
+openssl ec -in test_ec_key.pem -outform DER -out test_ec_key.der
+
+# computes the sha256 and saves it in binary form
+openssl sha256 -out test_ec_pub_sha256.bin -sha256 -binary < test_ec_pub.der
+
+# Save the certificate in DER form, then get the SHA256 hash of it
+# These are similar to doing "openssl x509 -in test_rsa.crt -fingerprint -sha256"
+openssl x509 -outform DER -out test_ec_crt.der -in test_ec.crt
+openssl sha256 -out test_ec_crt_sha256.bin -sha256 -binary < test_ec_crt.der
+
+# To verify signing, we create a random buffer, then sign with a SHA256 digest
+
+openssl sha -sha256 -sign test_ec_key.pem -out test_random_bytes.sig_ec < test_random_bytes
+
+# the "-in test_rsa_pub_sha256.bin" is the binary digest we will sign.
+openssl rsautl -sign -inkey test_ec_key.pem -in test_ec_pub_sha256.bin -out test_ec_pub_sha256.bin.sig \ No newline at end of file
diff --git a/libparc/parc/security/test/README.symmetric b/libparc/parc/security/test/README.symmetric
new file mode 100644
index 00000000..ce09fe85
--- /dev/null
+++ b/libparc/parc/security/test/README.symmetric
@@ -0,0 +1,9 @@
+
+# random bytes as a 32-byte (256-bit) key
+
+dd if=/dev/random of=test_symmetric_key.bin bs=32 count=1
+
+# compute its sha-256 hash
+openssl sha256 -binary -out test_symmetric_key.sha256 < test_symmetric_key.bin
+
+
diff --git a/libparc/parc/security/test/test.crt.der b/libparc/parc/security/test/test.crt.der
new file mode 100644
index 00000000..8b2e12ca
--- /dev/null
+++ b/libparc/parc/security/test/test.crt.der
Binary files differ
diff --git a/libparc/parc/security/test/test.crt.der.sha256.bin b/libparc/parc/security/test/test.crt.der.sha256.bin
new file mode 100644
index 00000000..1d19a81c
--- /dev/null
+++ b/libparc/parc/security/test/test.crt.der.sha256.bin
@@ -0,0 +1 @@
+öë>² âÜÔ¹±/Í©p 󨱅˜©È:), \ No newline at end of file
diff --git a/libparc/parc/security/test/test.der b/libparc/parc/security/test/test.der
new file mode 100644
index 00000000..db368b72
--- /dev/null
+++ b/libparc/parc/security/test/test.der
Binary files differ
diff --git a/libparc/parc/security/test/test.pem b/libparc/parc/security/test/test.pem
new file mode 100644
index 00000000..d9593bac
--- /dev/null
+++ b/libparc/parc/security/test/test.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICATCCAWoCCQDCCG74+EassjANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
+VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMB4XDTE1MDkwMzIxMDYxNloXDTE2MDkwMjIxMDYxNlowRTELMAkG
+A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvp5L
+B7ccwPfBooRduHvQHgJo5gvDIXX5dFz/8oRDgyAnvtvCoQXkfSj5oO+6WpaKIG2k
+RxO+2VEKknY1GyWT3qqHVfSgp33n/AKBsedVb5ZUVAhy4FAOq3BCF8wpfKrkfadQ
+ltmBNYP0DH4YdIvS7+HL5yaKXF1ZnUwWo2WFcucCAwEAATANBgkqhkiG9w0BAQUF
+AAOBgQAt8Op2KgQ6cREBVS6xOWvSeNr7/EXEW8T19BsUkYZeZ596oEJVjT2CrT0P
+s2ADuzfN0w19aGM25UczlBcg/CtkrTZEoXubbIoPGwwZv+taM+v455DhJY1chd0j
+Jq6XeRDokTFvn9qcZmoCX2CVKEMigatTpz4zenATUQmmRwdIVg==
+-----END CERTIFICATE-----
diff --git a/libparc/parc/security/test/test.pkcs12 b/libparc/parc/security/test/test.pkcs12
new file mode 100644
index 00000000..4b032263
--- /dev/null
+++ b/libparc/parc/security/test/test.pkcs12
Binary files differ
diff --git a/libparc/parc/security/test/test_crt.der b/libparc/parc/security/test/test_crt.der
new file mode 100644
index 00000000..42a829ee
--- /dev/null
+++ b/libparc/parc/security/test/test_crt.der
Binary files differ
diff --git a/libparc/parc/security/test/test_crt_der.bin b/libparc/parc/security/test/test_crt_der.bin
new file mode 100644
index 00000000..42a829ee
--- /dev/null
+++ b/libparc/parc/security/test/test_crt_der.bin
Binary files differ
diff --git a/libparc/parc/security/test/test_crt_sha256.bin b/libparc/parc/security/test/test_crt_sha256.bin
new file mode 100644
index 00000000..77d41680
--- /dev/null
+++ b/libparc/parc/security/test/test_crt_sha256.bin
@@ -0,0 +1 @@
+É5À#LGÇÎ4%uEN‡lní‚×êa,*V<w \ No newline at end of file
diff --git a/libparc/parc/security/test/test_der.bin b/libparc/parc/security/test/test_der.bin
new file mode 100644
index 00000000..db368b72
--- /dev/null
+++ b/libparc/parc/security/test/test_der.bin
Binary files differ
diff --git a/libparc/parc/security/test/test_digest_bytes_128.bin b/libparc/parc/security/test/test_digest_bytes_128.bin
new file mode 100644
index 00000000..b6939de1
--- /dev/null
+++ b/libparc/parc/security/test/test_digest_bytes_128.bin
@@ -0,0 +1 @@
+áã}/¼W9^Y(¾Î‘v»|é²}w‰“λ^…õK…¤ 3³õq˜hÜ%´Çanä™÷çĺEvuË.¹öÿºcÆóɪ¡Œÿ”›Ÿ¶¸ØC„óíjá'ŸDv\ÛhúêèE6™$ƒ]†ý[žúòÔlB¶}D©S \ No newline at end of file
diff --git a/libparc/parc/security/test/test_digest_bytes_128.sha256 b/libparc/parc/security/test/test_digest_bytes_128.sha256
new file mode 100644
index 00000000..6e93005d
--- /dev/null
+++ b/libparc/parc/security/test/test_digest_bytes_128.sha256
@@ -0,0 +1 @@
+ÛNôLæÛ.œœý†ûTŸëíàŒ`+Ûª¼]½· \ No newline at end of file
diff --git a/libparc/parc/security/test/test_digest_bytes_128.sha512 b/libparc/parc/security/test/test_digest_bytes_128.sha512
new file mode 100644
index 00000000..88db6953
--- /dev/null
+++ b/libparc/parc/security/test/test_digest_bytes_128.sha512
@@ -0,0 +1 @@
+W áJuieƒ>Â]„ϲ ý‚²åOC>4Gšßû ŠÆÖÏKNõEµÜE¦oÞp9~€‹kMÆòâLƒ¹ \ No newline at end of file
diff --git a/libparc/parc/security/test/test_ec.crt b/libparc/parc/security/test/test_ec.crt
new file mode 100644
index 00000000..69c446c2
--- /dev/null
+++ b/libparc/parc/security/test/test_ec.crt
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBsjCCAVkCCQDTJPDkG9R7gjAKBggqhkjOPQQDAjBjMQswCQYDVQQGEwJGUjEP
+MA0GA1UECAwGRnJhbmNlMRwwGgYDVQQHDBNJc3N5LWxlcy1tb3VsaW5lYXV4MRYw
+FAYDVQQKDA1DaXNjbyBTeXN0ZW1zMQ0wCwYDVQQLDARDVEFPMB4XDTE4MDQxMTEw
+MDYzNVoXDTE5MDQxMTEwMDYzNVowYzELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZy
+YW5jZTEcMBoGA1UEBwwTSXNzeS1sZXMtbW91bGluZWF1eDEWMBQGA1UECgwNQ2lz
+Y28gU3lzdGVtczENMAsGA1UECwwEQ1RBTzBWMBAGByqGSM49AgEGBSuBBAAKA0IA
+BKl0iUeCpxrOueZrbZLiWMhs7PAGgNYt+x4koWPJ0wELrbs7oNIqys8mJXQM9oTw
+I1b4IIgloT7/VcPanz66NgcwCgYIKoZIzj0EAwIDRwAwRAIgSc4s8ZKkEmuyV8wO
+08C58dN3dxXVYdW1v1zt3lq88dwCICf64KpJok1MGSX/t/QldOiVqPtPAv6l4lq2
+9EiLK+m9
+-----END CERTIFICATE-----
diff --git a/libparc/parc/security/test/test_ec.csr b/libparc/parc/security/test/test_ec.csr
new file mode 100644
index 00000000..49247a4e
--- /dev/null
+++ b/libparc/parc/security/test/test_ec.csr
@@ -0,0 +1,8 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIBGzCBwgIBADBjMQswCQYDVQQGEwJGUjEPMA0GA1UECAwGRnJhbmNlMRwwGgYD
+VQQHDBNJc3N5LWxlcy1tb3VsaW5lYXV4MRYwFAYDVQQKDA1DaXNjbyBTeXN0ZW1z
+MQ0wCwYDVQQLDARDVEFPMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEqXSJR4KnGs65
+5mttkuJYyGzs8AaA1i37HiShY8nTAQutuzug0irKzyYldAz2hPAjVvggiCWhPv9V
+w9qfPro2B6AAMAoGCCqGSM49BAMCA0gAMEUCIQCCQ5E36YNPG5LV2Q8i9flCPWk+
+4MjtioNV2I+NSf/6XgIgUjEeA54lw5dS8yqAkH8TDvw6ROe90rzBAfjsI1X2Y0k=
+-----END CERTIFICATE REQUEST-----
diff --git a/libparc/parc/security/test/test_ec.p12 b/libparc/parc/security/test/test_ec.p12
new file mode 100644
index 00000000..5fb44d05
--- /dev/null
+++ b/libparc/parc/security/test/test_ec.p12
Binary files differ
diff --git a/libparc/parc/security/test/test_ec_crt.der b/libparc/parc/security/test/test_ec_crt.der
new file mode 100644
index 00000000..d3294e20
--- /dev/null
+++ b/libparc/parc/security/test/test_ec_crt.der
Binary files differ
diff --git a/libparc/parc/security/test/test_ec_crt_sha256.bin b/libparc/parc/security/test/test_ec_crt_sha256.bin
new file mode 100644
index 00000000..22d1e2c4
--- /dev/null
+++ b/libparc/parc/security/test/test_ec_crt_sha256.bin
@@ -0,0 +1 @@
+Ý!bL?åœ'Âkàçllýã!çT°ƒh é~ï–z~p` \ No newline at end of file
diff --git a/libparc/parc/security/test/test_ec_key.der b/libparc/parc/security/test/test_ec_key.der
new file mode 100644
index 00000000..28fbd5a5
--- /dev/null
+++ b/libparc/parc/security/test/test_ec_key.der
Binary files differ
diff --git a/libparc/parc/security/test/test_ec_key.pem b/libparc/parc/security/test/test_ec_key.pem
new file mode 100644
index 00000000..6b0e1941
--- /dev/null
+++ b/libparc/parc/security/test/test_ec_key.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHQCAQEEIJXMLfUwhGUPNiXdmfpvWtfLzRSTL2fm9s+lTLCBGRdVoAcGBSuBBAAK
+oUQDQgAEqXSJR4KnGs655mttkuJYyGzs8AaA1i37HiShY8nTAQutuzug0irKzyYl
+dAz2hPAjVvggiCWhPv9Vw9qfPro2Bw==
+-----END EC PRIVATE KEY-----
diff --git a/libparc/parc/security/test/test_ec_pub.der b/libparc/parc/security/test/test_ec_pub.der
new file mode 100644
index 00000000..e9150405
--- /dev/null
+++ b/libparc/parc/security/test/test_ec_pub.der
Binary files differ
diff --git a/libparc/parc/security/test/test_ec_pub.pem b/libparc/parc/security/test/test_ec_pub.pem
new file mode 100644
index 00000000..2ab68ff8
--- /dev/null
+++ b/libparc/parc/security/test/test_ec_pub.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEqXSJR4KnGs655mttkuJYyGzs8AaA1i37
+HiShY8nTAQutuzug0irKzyYldAz2hPAjVvggiCWhPv9Vw9qfPro2Bw==
+-----END PUBLIC KEY-----
diff --git a/libparc/parc/security/test/test_ec_pub_sha256.bin b/libparc/parc/security/test/test_ec_pub_sha256.bin
new file mode 100644
index 00000000..c0dd0fac
--- /dev/null
+++ b/libparc/parc/security/test/test_ec_pub_sha256.bin
@@ -0,0 +1 @@
+1&,@‡‰ n Èå š„t©¢-DÔ|Œ¶>%—õžz` \ No newline at end of file
diff --git a/libparc/parc/security/test/test_ec_pub_sha256.bin.sig b/libparc/parc/security/test/test_ec_pub_sha256.bin.sig
new file mode 100644
index 00000000..787f8b3a
--- /dev/null
+++ b/libparc/parc/security/test/test_ec_pub_sha256.bin.sig
Binary files differ
diff --git a/libparc/parc/security/test/test_key.pem b/libparc/parc/security/test/test_key.pem
new file mode 100644
index 00000000..bdc42c1e
--- /dev/null
+++ b/libparc/parc/security/test/test_key.pem
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+nksHtxzA98GihF24e9AeAmjm
+C8Mhdfl0XP/yhEODICe+28KhBeR9KPmg77paloogbaRHE77ZUQqSdjUbJZPeqodV
+9KCnfef8AoGx51VvllRUCHLgUA6rcEIXzCl8quR9p1CW2YE1g/QMfhh0i9Lv4cvn
+JopcXVmdTBajZYVy5wIDAQAB
+-----END PUBLIC KEY-----
diff --git a/libparc/parc/security/test/test_parc_Certificate.c b/libparc/parc/security/test/test_parc_Certificate.c
new file mode 100644
index 00000000..24f46f86
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_Certificate.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 <LongBow/unit-test.h>
+
+#include "../parc_Certificate.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_Key.h>
+#include <parc/algol/parc_Buffer.h>
+
+PARCCryptoHash *
+_mockGetPublicKeyDigest(void *instance)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+ parcBuffer_Release(&buffer);
+ return hash;
+}
+
+PARCCryptoHash *
+_mockGetCertificateDigest(void *instance)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(20);
+ PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+ parcBuffer_Release(&buffer);
+ return hash;
+}
+
+PARCBuffer *
+_mockGetDEREncodedCertificate(void *instance)
+{
+ return parcBuffer_Allocate(30);
+}
+
+PARCBuffer *
+_mockGetDEREncodedPublicKey(void *instance)
+{
+ return parcBuffer_Allocate(40);
+}
+
+PARCCertificateType
+_mockGetCertificateType(const void *instance)
+{
+ return PARCCertificateType_X509;
+}
+
+PARCContainerEncoding
+_mockGetContainerEncoding(const void *instance)
+{
+ return PARCContainerEncoding_PEM;
+}
+
+PARCKey *
+_mockGetPublicKey(void *instance)
+{
+ PARCBuffer *realKey = parcBuffer_Allocate(256);
+ PARCBuffer *keyId = parcBuffer_Allocate(256);
+ PARCKeyId *id = parcKeyId_Create(keyId);
+
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(id, PARCSigningAlgorithm_RSA, realKey);
+
+ parcBuffer_Release(&keyId);
+ parcKeyId_Release(&id);
+ parcBuffer_Release(&realKey);
+
+ return key;
+}
+
+PARCCertificateInterface *_mockCertificate = &(PARCCertificateInterface) {
+ .GetPublicKeyDigest = _mockGetPublicKeyDigest,
+ .GetCertificateDigest = _mockGetCertificateDigest,
+ .GetDEREncodedCertificate = _mockGetDEREncodedCertificate,
+ .GetDEREncodedPublicKey = _mockGetDEREncodedPublicKey,
+ .GetCertificateType = _mockGetCertificateType,
+ .GetContainerEncoding = _mockGetContainerEncoding
+};
+
+LONGBOW_TEST_RUNNER(parc_Certificate)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parc_Certificate)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Certificate)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_GetContainerEncoding);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_GetCertificateType);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_GetPublicKeyDigest);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_GetCertificateDigest);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_GetDEREncodedCertificate);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_GetDEREncodedPublicKey);
+ LONGBOW_RUN_TEST_CASE(Global, parc_Certificate_GetPublicKey);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ 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(Global, parc_Certificate_AcquireRelease)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+ assertNotNull(certificate, "Expected non-NULL certificate");
+
+ PARCReferenceCount firstCount = parcObject_GetReferenceCount(certificate);
+ PARCCertificate *copy = parcCertificate_Acquire(certificate);
+ PARCReferenceCount secondCount = parcObject_GetReferenceCount(copy);
+
+ assertTrue(firstCount == (secondCount - 1), "Expected incremented reference count after Acquire");
+
+ parcCertificate_Release(&copy);
+ PARCReferenceCount thirdCount = parcObject_GetReferenceCount(certificate);
+
+ assertTrue(firstCount == thirdCount, "Expected equal reference counts after Release");
+
+ parcCertificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Certificate_Create)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+
+ assertNotNull(certificate, "Expected non-NULL certificate");
+
+ parcCertificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Certificate_GetContainerEncoding)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+ PARCContainerEncoding encoding = parcCertificate_GetContainerEncoding(certificate);
+ assertTrue(encoding == PARCContainerEncoding_PEM, "Expected %d, got %d", PARCContainerEncoding_PEM, encoding);
+ parcCertificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Certificate_GetCertificateType)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+ PARCCertificateType type = parcCertificate_GetCertificateType(certificate);
+ assertTrue(type == PARCCertificateType_X509, "Expected %d, got %d", PARCCertificateType_X509, type);
+ parcCertificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Certificate_GetPublicKeyDigest)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+
+ PARCCryptoHash *hash = parcCertificate_GetPublicKeyDigest(certificate);
+ size_t length = parcBuffer_Remaining(parcCryptoHash_GetDigest(hash));
+ size_t expected = 10;
+ assertTrue(length == expected, "Expected length of %zu, got %zu", expected, length);
+
+ parcCryptoHash_Release(&hash);
+ parcCertificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Certificate_GetCertificateDigest)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+
+ PARCCryptoHash *hash = parcCertificate_GetCertificateDigest(certificate);
+ size_t length = parcBuffer_Remaining(parcCryptoHash_GetDigest(hash));
+ size_t expected = 20;
+ assertTrue(length == expected, "Expected length of %zu, got %zu", expected, length);
+
+ parcCryptoHash_Release(&hash);
+ parcCertificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Certificate_GetDEREncodedCertificate)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+
+ PARCBuffer *buffer = parcCertificate_GetDEREncodedCertificate(certificate);
+ size_t length = parcBuffer_Remaining(buffer);
+ size_t expected = 30;
+ assertTrue(length == expected, "Expected length of %zu, got %zu", expected, length);
+
+ parcBuffer_Release(&buffer);
+ parcCertificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Certificate_GetDEREncodedPublicKey)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+
+ PARCBuffer *buffer = parcCertificate_GetDEREncodedPublicKey(certificate);
+ size_t length = parcBuffer_Remaining(buffer);
+ size_t expected = 40;
+ assertTrue(length == expected, "Expected length of %zu, got %zu", expected, length);
+
+ parcBuffer_Release(&buffer);
+ parcCertificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_Certificate_GetPublicKey)
+{
+ PARCCertificate *certificate = parcCertificate_CreateFromInstance(_mockCertificate, NULL);
+
+ PARCKey *actual = parcCertificate_GetPublicKey(certificate);
+ assertTrue(parcBuffer_Remaining(parcKey_GetKey(actual)) == 40,
+ "Expected PARCKey size to be 40, got %zu",
+ parcBuffer_Remaining(parcKey_GetKey(actual)));
+ assertTrue(parcBuffer_Remaining(parcKeyId_GetKeyId(parcKey_GetKeyId(actual))) == 10,
+ "Expected PARCKey keyId size to be 10, got %zu",
+ parcBuffer_Remaining(parcKeyId_GetKeyId(parcKey_GetKeyId(actual))));
+
+ parcKey_Release(&actual);
+ parcCertificate_Release(&certificate);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Certificate);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_CertificateFactory.c b/libparc/parc/security/test/test_parc_CertificateFactory.c
new file mode 100755
index 00000000..29675f94
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_CertificateFactory.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 <LongBow/unit-test.h>
+
+#include "../parc_CertificateFactory.c"
+#include <parc/security/parc_X509Certificate.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/algol/parc_Buffer.h>
+
+LONGBOW_TEST_RUNNER(parc_CertificateFactory)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parc_CertificateFactory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_CertificateFactory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_CertificateFactory_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parc_CertificateFactory_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parc_CertificateFactory_CreateFromFile);
+ LONGBOW_RUN_TEST_CASE(Global, parc_CertificateFactory_CreateFromBuffer);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ 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(Global, parc_CertificateFactory_AcquireRelease)
+{
+ PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_PEM);
+ assertNotNull(factory, "Expected non-NULL factory");
+
+ PARCReferenceCount firstCount = parcObject_GetReferenceCount(factory);
+ PARCCertificateFactory *copy = parcCertificateFactory_Acquire(factory);
+ PARCReferenceCount secondCount = parcObject_GetReferenceCount(copy);
+
+ assertTrue(firstCount == (secondCount - 1), "Expected incremented reference count after Acquire");
+
+ parcCertificateFactory_Release(&copy);
+ PARCReferenceCount thirdCount = parcObject_GetReferenceCount(factory);
+
+ assertTrue(firstCount == thirdCount, "Expected equal reference counts after Release");
+
+ parcCertificateFactory_Release(&factory);
+}
+
+LONGBOW_TEST_CASE(Global, parc_CertificateFactory_Create)
+{
+ PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_PEM);
+ assertNotNull(factory, "Expected non-NULL factory");
+ assertTrue(factory->encoding == PARCContainerEncoding_PEM, "Expected PARCContainerEncoding_PEM (%d) encoding, got %d",
+ PARCContainerEncoding_PEM, factory->encoding);
+ assertTrue(factory->type == PARCCertificateType_X509, "Expected PARCCertificateType_X509 (%d) type, got %d",
+ PARCCertificateType_X509, factory->type);
+ parcCertificateFactory_Release(&factory);
+}
+
+LONGBOW_TEST_CASE(Global, parc_CertificateFactory_CreateFromFile)
+{
+ PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_PEM);
+ assertNotNull(factory, "Expected non-NULL factory");
+
+ char *filename = "test.pem";
+ PARCCertificate *certificate = parcCertificateFactory_CreateCertificateFromFile(factory, filename, NULL);
+
+ assertNotNull(certificate, "Expected non-NULL certificate");
+ assertTrue(parcCertificate_GetContainerEncoding(certificate) == PARCContainerEncoding_PEM,
+ "Expected PARCContainerEncoding_PEM encoding, got %d", parcCertificate_GetContainerEncoding(certificate));
+ assertTrue(parcCertificate_GetCertificateType(certificate) == PARCCertificateType_X509,
+ "Expected PARCCertificateType_X509 type, got %d", parcCertificate_GetCertificateType(certificate));
+
+ parcCertificate_Release(&certificate);
+ parcCertificateFactory_Release(&factory);
+
+ factory = parcCertificateFactory_Create(PARCCertificateType_Invalid, PARCContainerEncoding_PEM);
+
+ PARCCertificate *nullCertificate = parcCertificateFactory_CreateCertificateFromFile(factory, filename, NULL);
+ assertNull(nullCertificate, "Expected NULL certificate to be returned from factory with an unsupported configuration");
+
+ parcCertificateFactory_Release(&factory);
+}
+
+LONGBOW_TEST_CASE(Global, parc_CertificateFactory_CreateFromBuffer)
+{
+ PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509, PARCContainerEncoding_DER);
+ assertNotNull(factory, "Expected non-NULL factory");
+
+ char *filename = "test.pem";
+ PARCX509Certificate *realCertificate = parcX509Certificate_CreateFromPEMFile(filename);
+ PARCBuffer *certificateBuffer = parcX509Certificate_GetDEREncodedCertificate(realCertificate);
+
+ PARCCertificate *certificate = parcCertificateFactory_CreateCertificateFromBuffer(factory, certificateBuffer);
+
+ assertNotNull(certificate, "Expected non-NULL certificate");
+ assertTrue(parcCertificate_GetContainerEncoding(certificate) == PARCContainerEncoding_DER,
+ "Expected PARCContainerEncoding_DER encoding, got %d", parcCertificate_GetContainerEncoding(certificate));
+ assertTrue(parcCertificate_GetCertificateType(certificate) == PARCCertificateType_X509,
+ "Expected PARCCertificateType_X509 type, got %d", parcCertificate_GetCertificateType(certificate));
+
+ parcCertificate_Release(&certificate);
+ parcCertificateFactory_Release(&factory);
+ parcX509Certificate_Release(&realCertificate);
+
+ factory = parcCertificateFactory_Create(PARCCertificateType_Invalid, PARCContainerEncoding_PEM);
+
+ PARCBuffer *invalid = parcBuffer_Allocate(10);
+ PARCCertificate *nullCertificate = parcCertificateFactory_CreateCertificateFromBuffer(factory, invalid);
+ assertNull(nullCertificate, "Expected NULL certificate to be returned from factory with an unsupported configuration");
+
+ parcBuffer_Release(&invalid);
+ parcCertificateFactory_Release(&factory);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_CertificateFactory);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_CertificateType.c b/libparc/parc/security/test/test_parc_CertificateType.c
new file mode 100755
index 00000000..67ce5e87
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_CertificateType.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.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <LongBow/unit-test.h>
+
+#include "../parc_CertificateType.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/algol/parc_Buffer.h>
+
+LONGBOW_TEST_RUNNER(parc_CertificateType)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parc_CertificateType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_CertificateType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_CertificateType_FromString);
+ LONGBOW_RUN_TEST_CASE(Global, parc_CertificateType_ToString);
+}
+
+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, parc_CertificateType_FromString)
+{
+ char *inputString = "PARCCertificateType_X509";
+ PARCCertificateType encoding = parcCertificateType_FromString(inputString);
+ assertTrue(encoding == PARCCertificateType_X509, "Expected PARCCertificateType_X509 (%d), for %d", PARCCertificateType_X509, encoding);
+
+ inputString = "the cake is a lie";
+ encoding = parcCertificateType_FromString(inputString);
+ assertTrue(encoding == PARCCertificateType_Invalid, "Expected PARCCertificateType_Invalid (%d), for %d", PARCCertificateType_Invalid, encoding);
+}
+
+LONGBOW_TEST_CASE(Global, parc_CertificateType_ToString)
+{
+ char *expected = "PARCCertificateType_X509";
+ PARCCertificateType encoding = PARCCertificateType_X509;
+ const char *actual = parcCertificateType_ToString(encoding);
+ assertTrue(strcmp(actual, expected) == 0, "Expected %s, got %s", expected, actual);
+
+ actual = parcCertificateType_ToString(PARCCertificateType_Invalid);
+ assertNull(actual, "Expected NULL string to be returned with invalid certificate type");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_CertificateType);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_ContainerEncoding.c b/libparc/parc/security/test/test_parc_ContainerEncoding.c
new file mode 100755
index 00000000..01cafa50
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_ContainerEncoding.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.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <LongBow/unit-test.h>
+
+#include "../parc_ContainerEncoding.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/algol/parc_Buffer.h>
+
+LONGBOW_TEST_RUNNER(parc_ContainerEncoding)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parc_ContainerEncoding)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_ContainerEncoding)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_ContainerEncoding_FromString);
+ LONGBOW_RUN_TEST_CASE(Global, parc_ContainerEncoding_ToString);
+}
+
+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, parc_ContainerEncoding_FromString)
+{
+ char *inputString = "PARCContainerEncoding_PEM";
+ PARCContainerEncoding encoding = parcContainerEncoding_FromString(inputString);
+ assertTrue(encoding == PARCContainerEncoding_PEM, "Expected PARCContainerEncoding_PEM (%d), for %d", PARCContainerEncoding_PEM, encoding);
+
+ inputString = "the cake is a lie";
+ encoding = parcContainerEncoding_FromString(inputString);
+ assertTrue(encoding == PARCContainerEncoding_Invalid, "Expected PARCContainerEncoding_Invalid (%d), for %d", PARCContainerEncoding_Invalid, encoding);
+}
+
+LONGBOW_TEST_CASE(Global, parc_ContainerEncoding_ToString)
+{
+ char *expected = "PARCContainerEncoding_PEM";
+ PARCContainerEncoding encoding = PARCContainerEncoding_PEM;
+ const char *actual = parcContainerEncoding_ToString(encoding);
+ assertTrue(strcmp(actual, expected) == 0, "Expected %s, got %s", expected, actual);
+
+ actual = parcContainerEncoding_ToString(PARCContainerEncoding_Invalid);
+ assertNull(actual, "Expected NULL string to be returned with invalid encoding type");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_ContainerEncoding);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_CryptoCache.c b/libparc/parc/security/test/test_parc_CryptoCache.c
new file mode 100755
index 00000000..8613808d
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_CryptoCache.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/unit-test.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_CryptoCache.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/security/parc_CryptoHashType.h>
+
+LONGBOW_TEST_RUNNER(parc_CryptoCache)
+{
+ // 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(Allocate);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_CryptoCache)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_CryptoCache)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Allocate)
+{
+ LONGBOW_RUN_TEST_CASE(Allocate, parcCryptoCache_Create_Destroy);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Allocate)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Allocate)
+{
+ 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(Allocate, parcCryptoCache_Create_Destroy)
+{
+ PARCCryptoCache *cache = parcCryptoCache_Create();
+ parcCryptoCache_Destroy(&cache);
+}
+
+static PARCCryptoCache *cache_under_test;
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoCache_AddGetKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoCache_GetMissingKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoCache_GetWrongKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoCache_RemoveKey);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ cache_under_test = parcCryptoCache_Create();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ parcCryptoCache_Destroy(&cache_under_test);
+
+ 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, parcCryptoCache_AddGetKey)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+
+ parcCryptoCache_AddKey(cache_under_test, key);
+
+ const PARCKey *test = parcCryptoCache_GetKey(cache_under_test, keyid);
+
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+
+ assertTrue(parcKey_Equals(key, test), "did not return expected key from cache");
+ parcKey_Release(&key);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoCache_GetMissingKey)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ const PARCKey *test = parcCryptoCache_GetKey(cache_under_test, keyid);
+
+ assertNull(test, "Get missing key returned something!");
+
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoCache_GetWrongKey)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCBuffer *bb_id2 = parcBuffer_Wrap("not here!", 9, 0, 9);
+
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCKeyId *keyid2 = parcKeyId_Create(bb_id2);
+ parcBuffer_Release(&bb_id2);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+
+ parcCryptoCache_AddKey(cache_under_test, key);
+
+ const PARCKey *test = parcCryptoCache_GetKey(cache_under_test, keyid2);
+ assertNull(test, "Get missing key returned something!");
+
+ parcKey_Release(&key);
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+ parcKeyId_Release(&keyid2);
+}
+
+/**
+ * Add in 2 keys, remove 1, fetch the other
+ */
+LONGBOW_TEST_CASE(Global, parcCryptoCache_RemoveKey)
+{
+ PARCBufferComposer *composer1 = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer1, "quack quack");
+ PARCBuffer *bb_key1 = parcBufferComposer_ProduceBuffer(composer1);
+
+ PARCBufferComposer *composer2 = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer2, "Come with me and you'll be");
+ PARCBuffer *bb_key2 = parcBufferComposer_ProduceBuffer(composer2);
+
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCBuffer *bb_id2 = parcBuffer_Wrap("not here!", 9, 0, 9);
+
+ PARCKeyId *keyid1 = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+ PARCKeyId *keyid2 = parcKeyId_Create(bb_id2);
+ parcBuffer_Release(&bb_id2);
+
+ PARCKey *key1 = parcKey_CreateFromDerEncodedPublicKey(keyid1, PARCSigningAlgorithm_RSA, bb_key1);
+ PARCKey *key2 = parcKey_CreateFromDerEncodedPublicKey(keyid2, PARCSigningAlgorithm_RSA, bb_key2);
+ const PARCKey *test;
+
+ parcCryptoCache_AddKey(cache_under_test, key1);
+ parcCryptoCache_AddKey(cache_under_test, key2);
+
+ test = parcCryptoCache_GetKey(cache_under_test, keyid1);
+ assertTrue(parcKey_Equals(key1, test), "Got wrong key");
+
+ test = parcCryptoCache_GetKey(cache_under_test, keyid2);
+ assertTrue(parcKey_Equals(key2, test), "Got wrong key");
+
+ // remove will free the key, so make a copy of it before removing
+ PARCKeyId *keyid1_copy = parcKeyId_Copy(keyid1);
+ parcCryptoCache_RemoveKey(cache_under_test, keyid1);
+
+ test = parcCryptoCache_GetKey(cache_under_test, keyid1_copy);
+ assertNull(test, "Get of deleted key returned non-null");
+
+ test = parcCryptoCache_GetKey(cache_under_test, keyid2);
+ assertTrue(parcKey_Equals(key2, test), "Got wrong key");
+
+
+ parcKey_Release(&key1);
+ parcKey_Release(&key2);
+
+ parcBuffer_Release(&bb_key1);
+ parcBufferComposer_Release(&composer1);
+ parcKeyId_Release(&keyid1);
+ parcBuffer_Release(&bb_key2);
+ parcBufferComposer_Release(&composer2);
+ parcKeyId_Release(&keyid2);
+
+ parcKeyId_Release(&keyid1_copy);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_CryptoCache);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_CryptoHash.c b/libparc/parc/security/test/test_parc_CryptoHash.c
new file mode 100755
index 00000000..df5409b2
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_CryptoHash.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_CryptoHash.c"
+#include "../parc_CryptoHasher.h"
+
+#include <LongBow/unit-test.h>
+#include <parc/testing/parc_ObjectTesting.h>
+#include <fcntl.h>
+#include <errno.h>
+
+const int bufferLength = 1024;
+
+LONGBOW_TEST_RUNNER(parc_CryptoHash)
+{
+ // 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(parc_CryptoHash)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_CryptoHash)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHash_CreateFromArray);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHash_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHash_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHash_GetDigest);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHash_GetDigestType);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHash_CreateFromArray)
+{
+ int fd = open("test_digest_bytes_128.sha256", O_RDONLY);
+ assertFalse(fd < 0, "Could not open %s: %s", "test_digest_bytes_128.sha256", strerror(errno));
+
+ uint8_t scratch[bufferLength];
+ ssize_t read_length = read(fd, scratch, bufferLength);
+
+ PARCCryptoHash *hash = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch, read_length);
+ assertNotNull(hash, "Expected to be non null");
+
+ parcCryptoHash_Release(&hash);
+ close(fd);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHash_Release)
+{
+ int fd = open("test_digest_bytes_128.sha256", O_RDONLY);
+ assertFalse(fd < 0, "Could not open %s: %s", "test_digest_bytes_128.sha256", strerror(errno));
+
+ uint8_t scratch[bufferLength];
+ ssize_t read_length = read(fd, scratch, bufferLength);
+
+ PARCCryptoHash *hash = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch, read_length);
+ assertNotNull(hash, "Expected to be non null");
+
+ parcCryptoHash_Release(&hash);
+ assertNull(hash, "Expected to be null");
+ close(fd);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHash_Equals)
+{
+ int fd1 = open("test_digest_bytes_128.sha256", O_RDONLY);
+ assertFalse(fd1 < 0, "Could not open %s: %s", "test_digest_bytes_128.sha256", strerror(errno));
+
+ uint8_t scratch1[bufferLength];
+ ssize_t read_length = read(fd1, scratch1, bufferLength);
+
+ PARCCryptoHash *hash1 = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch1, read_length);
+ PARCCryptoHash *hash2 = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch1, read_length);
+ PARCCryptoHash *hash3 = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch1, read_length);
+
+ int fd2 = open("test_digest_bytes_128.sha512", O_RDONLY);
+ assertFalse(fd2 < 0, "Could not open %s: %s", "test_digest_bytes_128.sha512", strerror(errno));
+
+ uint8_t scratch2[bufferLength];
+ read_length = read(fd2, scratch2, bufferLength);
+
+ PARCCryptoHash *unequalhash = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch2, read_length);
+
+ parcObjectTesting_AssertEqualsFunction(parcObject_Equals, hash1, hash2, hash3, unequalhash);
+
+ parcCryptoHash_Release(&hash1);
+ parcCryptoHash_Release(&hash2);
+ parcCryptoHash_Release(&hash3);
+ parcCryptoHash_Release(&unequalhash);
+
+ close(fd1);
+ close(fd2);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHash_GetDigest)
+{
+ int fd_buffer = open("test_digest_bytes_128.bin", O_RDONLY);
+ int fd_truth = open("test_digest_bytes_128.sha256", O_RDONLY);
+ assertFalse(fd_buffer < 0, "Could not open %s: %s", "test_digest_bytes_128.bin", strerror(errno));
+ assertFalse(fd_truth < 0, "Could not open %s: %s", "test_digest_bytes_128.sha256", strerror(errno));
+
+ uint8_t scratch[bufferLength];
+ ssize_t read_length = read(fd_truth, scratch, bufferLength);
+
+ PARCCryptoHash *hashTruth = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch, read_length);
+
+ read_length = read(fd_buffer, scratch, bufferLength);
+
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBytes(hasher, scratch, read_length);
+
+ PARCCryptoHash *hashTest = parcCryptoHasher_Finalize(hasher);
+
+ assertTrue(parcBuffer_Equals(parcCryptoHash_GetDigest(hashTruth), parcCryptoHash_GetDigest(hashTest)), "Expected to be true");
+
+ parcCryptoHasher_Release(&hasher);
+ parcCryptoHash_Release(&hashTruth);
+ parcCryptoHash_Release(&hashTest);
+
+ close(fd_buffer);
+ close(fd_truth);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHash_GetDigestType)
+{
+ int fd = open("test_digest_bytes_128.sha256", O_RDONLY);
+ assertFalse(fd < 0, "Could not open %s: %s", "test_digest_bytes_128.sha256", strerror(errno));
+
+ uint8_t scratch[bufferLength];
+ ssize_t read_length = read(fd, scratch, bufferLength);
+
+ PARCCryptoHash *hash = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch, read_length);
+ assertNotNull(hash, "Expected to be non null");
+
+ assertTrue(PARCCryptoHashType_SHA256 == parcCryptoHash_GetDigestType(hash), "Expected to be true");
+
+ parcCryptoHash_Release(&hash);
+ close(fd);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_CryptoHash);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_CryptoHashType.c b/libparc/parc/security/test/test_parc_CryptoHashType.c
new file mode 100644
index 00000000..1e1cc68b
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_CryptoHashType.c
@@ -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.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_CryptoHashType.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_CryptoHashType)
+{
+ // 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(parc_CryptoHashType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_CryptoHashType)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHashType_FromString);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHashType_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHashType_FromString)
+{
+ assertTrue(PARCCryptoHashType_SHA256 == parcCryptoHashType_FromString("PARCCryptoHashType_SHA256"), "Expected true");
+
+ assertTrue(PARCCryptoHashType_SHA512 == parcCryptoHashType_FromString("PARCCryptoHashType_SHA512"), "Expected true");
+
+ assertTrue(PARCCryptoHashType_CRC32C == parcCryptoHashType_FromString("PARCCryptoHashType_CRC32C"), "Expected true");
+
+ assertTrue(PARCCryptoHashType_NULL == parcCryptoHashType_FromString("NULL"), "Expected true");
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHashType_ToString)
+{
+ const char *string1 = parcCryptoHashType_ToString(PARCCryptoHashType_SHA256);
+ assertNotNull(string1, "Expected non-null result.");
+
+ const char *string2 = parcCryptoHashType_ToString(PARCCryptoHashType_SHA512);
+ assertNotNull(string2, "Expected non-null result.");
+
+ const char *string3 = parcCryptoHashType_ToString(PARCCryptoHashType_CRC32C);
+ assertNotNull(string3, "Expected non-null result.");
+
+ const char *string4 = parcCryptoHashType_ToString(PARCCryptoHashType_NULL);
+ assertNull(string4, "Expected to be null");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_CryptoHashType);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_CryptoHasher.c b/libparc/parc/security/test/test_parc_CryptoHasher.c
new file mode 100755
index 00000000..33a3f6bc
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_CryptoHasher.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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_SafeMemory.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/security/parc_Security.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_CryptoHasher.c"
+
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+
+const int bufferLength = 1024;
+
+/*
+ * 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(parc_CryptoHasher)
+{
+ // 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(Performance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_CryptoHasher)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_CryptoHasher)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHasher_Create);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHasher_Bytes_256);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHasher_Buffer_256);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHasher_Bytes_512);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHasher_Buffer_512);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHasher_CRC32);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoHasher_CustomHasher);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ 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(Global, parcCryptoHasher_Create)
+{
+ PARCCryptoHasher *hasher;
+
+ hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Release(&hasher);
+
+ hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA512);
+ PARCCryptoHasher *handle = parcCryptoHasher_Acquire(hasher);
+
+ assertTrue(parcObject_GetReferenceCount(handle) == 2, "Expected 2 references");
+
+ parcCryptoHasher_Release(&hasher);
+ parcCryptoHasher_Release(&handle);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHasher_Bytes_256)
+{
+ int fd_buffer = open("test_digest_bytes_128.bin", O_RDONLY);
+ int fd_truth = open("test_digest_bytes_128.sha256", O_RDONLY);
+ assertFalse(fd_buffer < 0, "Could not open %s: %s", "test_digest_bytes_128.bin", strerror(errno));
+ assertFalse(fd_truth < 0, "Could not open %s: %s", "test_digest_bytes_128.sha256", strerror(errno));
+
+ uint8_t scratch[bufferLength];
+ ssize_t read_length;
+
+ read_length = read(fd_truth, scratch, bufferLength);
+
+ PARCCryptoHash *digestTruth = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch, read_length);
+
+ read_length = read(fd_buffer, scratch, bufferLength);
+
+ PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBytes(digester, scratch, read_length);
+
+ PARCCryptoHash *digestTest = parcCryptoHasher_Finalize(digester);
+
+ assertTrue(parcCryptoHash_Equals(digestTruth, digestTest),
+ "sha256 digest of 128-byte buffer using Update_Buffer does not match");
+
+ parcCryptoHasher_Release(&digester);
+ parcCryptoHash_Release(&digestTruth);
+ parcCryptoHash_Release(&digestTest);
+
+ close(fd_buffer);
+ close(fd_truth);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHasher_Buffer_256)
+{
+ int fd_buffer = open("test_digest_bytes_128.bin", O_RDONLY);
+ int fd_truth = open("test_digest_bytes_128.sha256", O_RDONLY);
+ assertFalse(fd_buffer < 0, "Could not open %s: %s", "test_digest_bytes_128.bin", strerror(errno));
+ assertFalse(fd_truth < 0, "Could not open %s: %s", "test_digest_bytes_128.sha256", strerror(errno));
+
+ uint8_t scratch[bufferLength];
+
+ ssize_t read_length = read(fd_buffer, scratch, bufferLength);
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer, scratch, read_length);
+ PARCBuffer *bb_to_digest = parcBufferComposer_ProduceBuffer(composer);
+
+ read_length = read(fd_truth, scratch, bufferLength);
+ PARCCryptoHash *digestTruth = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA256, scratch, read_length);
+
+ PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBuffer(digester, bb_to_digest);
+ PARCCryptoHash *digestTest = parcCryptoHasher_Finalize(digester);
+
+ assertTrue(parcCryptoHash_Equals(digestTruth, digestTest),
+ "sha256 digest of 128-byte buffer using Update_Buffer does not match");
+
+ parcCryptoHasher_Release(&digester);
+ parcBuffer_Release(&bb_to_digest);
+ parcBufferComposer_Release(&composer);
+ parcCryptoHash_Release(&digestTruth);
+ parcCryptoHash_Release(&digestTest);
+
+ close(fd_buffer);
+ close(fd_truth);
+}
+
+// ==== 512
+
+LONGBOW_TEST_CASE(Global, parcCryptoHasher_Bytes_512)
+{
+ PARCCryptoHasher *digester;
+
+ int fd_buffer = open("test_digest_bytes_128.bin", O_RDONLY);
+ int fd_truth = open("test_digest_bytes_128.sha512", O_RDONLY);
+ assertFalse(fd_buffer < 0, "Could not open %s: %s", "test_digest_bytes_128.bin", strerror(errno));
+ assertFalse(fd_truth < 0, "Could not open %s: %s", "test_digest_bytes_128.sha512", strerror(errno));
+
+ uint8_t scratch[bufferLength];
+ ssize_t read_length;
+
+ read_length = read(fd_truth, scratch, bufferLength);
+ PARCCryptoHash *digestTruth = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA512, scratch, read_length);
+
+ read_length = read(fd_buffer, scratch, bufferLength);
+
+
+ digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA512);
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBytes(digester, scratch, read_length);
+ PARCCryptoHash *digestTest = parcCryptoHasher_Finalize(digester);
+
+ assertTrue(parcCryptoHash_Equals(digestTruth, digestTest), "sha512 digest of 128-byte buffer using Update_Buffer does not match");
+
+ parcCryptoHasher_Release(&digester);
+ parcCryptoHash_Release(&digestTruth);
+ parcCryptoHash_Release(&digestTest);
+
+ close(fd_buffer);
+ close(fd_truth);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHasher_Buffer_512)
+{
+ int fd_buffer = open("test_digest_bytes_128.bin", O_RDONLY);
+ int fd_truth = open("test_digest_bytes_128.sha512", O_RDONLY);
+ assertFalse(fd_buffer < 0, "Could not open %s: %s", "test_digest_bytes_128.bin", strerror(errno));
+ assertFalse(fd_truth < 0, "Could not open %s: %s", "test_digest_bytes_128.sha512", strerror(errno));
+
+ uint8_t scratch[bufferLength];
+ ssize_t read_length;
+
+ read_length = read(fd_buffer, scratch, bufferLength);
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer, scratch, read_length);
+ PARCBuffer *bb_to_digest = parcBufferComposer_ProduceBuffer(composer);
+
+ read_length = read(fd_truth, scratch, bufferLength);
+ PARCCryptoHash *digestTruth = parcCryptoHash_CreateFromArray(PARCCryptoHashType_SHA512, scratch, read_length);
+
+ PARCCryptoHasher *digester = parcCryptoHasher_Create(PARCCryptoHashType_SHA512);
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBuffer(digester, bb_to_digest);
+ PARCCryptoHash *digestTest = parcCryptoHasher_Finalize(digester);
+
+ assertTrue(parcCryptoHash_Equals(digestTruth, digestTest),
+ "sha512 digest of 128-byte buffer using Update_Buffer does not match");
+
+ parcCryptoHasher_Release(&digester);
+ parcBuffer_Release(&bb_to_digest);
+ parcBufferComposer_Release(&composer);
+ parcCryptoHash_Release(&digestTruth);
+ parcCryptoHash_Release(&digestTest);
+
+ close(fd_buffer);
+ close(fd_truth);
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHasher_CRC32)
+{
+ for (int i = 0; vectors[i].buffer != NULL; i++) {
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_CRC32C);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBytes(hasher, vectors[i].buffer, vectors[i].length);
+ PARCCryptoHash *output = parcCryptoHasher_Finalize(hasher);
+ PARCBuffer *buffer = parcCryptoHash_GetDigest(output);
+ uint32_t testCrc = parcBuffer_GetUint32(buffer);
+ parcCryptoHash_Release(&output);
+
+ assertTrue(testCrc == vectors[i].crc32c,
+ "CRC32C values wrong, index %d got 0x%08x expected 0x%08x\n",
+ i, testCrc, vectors[i].crc32c);
+ parcCryptoHasher_Release(&hasher);
+ }
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoHasher_CustomHasher)
+{
+ PARCCryptoHasher *hasher = parcCryptoHasher_CustomHasher(PARCCryptoHashType_SHA512, functor_sha256);
+ assertNotNull(hasher, "Expected to be non null");
+
+ parcCryptoHasher_Release(&hasher);
+}
+
+// ================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, computeCrc32C_Software);
+}
+
+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, computeCrc32C_Software)
+{
+ for (int i = 0; vectors[i].buffer != NULL; i++) {
+ uint32_t testCrc = _crc32c_Init();
+ testCrc = _crc32c_UpdateSoftware(testCrc, vectors[i].length, vectors[i].buffer);
+ testCrc = _crc32c_Finalize(testCrc);
+
+ assertTrue(testCrc == vectors[i].crc32c,
+ "CRC32C values wrong, index %d got 0x%08x expected 0x%08x\n",
+ i, testCrc, vectors[i].crc32c);
+ }
+}
+
+// =======================================================
+
+LONGBOW_TEST_FIXTURE(Performance)
+{
+ LONGBOW_RUN_TEST_CASE(Performance, computeCrc32C);
+ LONGBOW_RUN_TEST_CASE(Performance, computeCrc32C_Software);
+}
+
+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;
+}
+
+static double
+runPerformance(int maxreps, uint32_t (*update)(uint32_t crc, size_t len, uint8_t p[len]))
+{
+ int reps = maxreps;
+ int length = 100;
+
+ uint8_t buffer[length];
+ for (int i = 0; i < length; i++) {
+ buffer[i] = i * 33;
+ }
+
+ // initial value doesnt really matter
+
+ struct timeval t0, t1;
+ gettimeofday(&t0, NULL);
+ while (--reps) {
+ uint32_t crc = _crc32c_Init();
+ update(crc, length, buffer);
+ crc = _crc32c_Finalize(crc);
+ }
+
+ gettimeofday(&t1, NULL);
+
+ timersub(&t1, &t0, &t1);
+
+ double seconds = t1.tv_sec + t1.tv_usec * 1E-6;
+ return seconds;
+}
+
+LONGBOW_TEST_CASE(Performance, computeCrc32C)
+{
+ int maxreps = 1000000;
+ double seconds = runPerformance(maxreps, _crc32c_Update);
+ double rate = maxreps / seconds;
+
+ printf("Best rate = %.3f for %d iterations\n", rate, maxreps);
+}
+
+LONGBOW_TEST_CASE(Performance, computeCrc32C_Software)
+{
+ int maxreps = 1000000;
+ double seconds = runPerformance(maxreps, _crc32c_UpdateSoftware);
+ double rate = maxreps / seconds;
+
+ printf("Best rate = %.3f for %d iterations\n", rate, maxreps);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_CryptoHasher);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_CryptoSuite.c b/libparc/parc/security/test/test_parc_CryptoSuite.c
new file mode 100755
index 00000000..42007617
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_CryptoSuite.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 "../parc_CryptoSuite.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_CryptoSuite)
+{
+ // 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(parc_CryptoSuite)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_CryptoSuite)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoSuite_GetCryptoHash);
+ LONGBOW_RUN_TEST_CASE(Global, parcCryptoSuite_GetCryptoHash_IllegalValue);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcCryptoSuite_GetCryptoHash)
+{
+ assertTrue(PARCCryptoHashType_SHA256 == parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_RSA_SHA256), "Expected to be true");
+ assertTrue(PARCCryptoHashType_SHA256 == parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_DSA_SHA256), "Expected to be true");
+ assertTrue(PARCCryptoHashType_SHA512 == parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_RSA_SHA512), "Expected to be true");
+ assertTrue(PARCCryptoHashType_SHA256 == parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_HMAC_SHA256), "Expected to be true");
+ assertTrue(PARCCryptoHashType_SHA512 == parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_HMAC_SHA512), "Expected to be true");
+ assertTrue(PARCCryptoHashType_CRC32C == parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_NULL_CRC32C), "Expected to be true");
+ assertTrue(PARCCryptoHashType_SHA256 == parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_ECDSA_SHA256), "Expected to be true");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcCryptoSuite_GetCryptoHash_IllegalValue, .event = &LongBowTrapIllegalValue)
+{
+ parcCryptoSuite_GetCryptoHash(PARCCryptoSuite_UNKNOWN);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_CryptoSuite);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_DiffieHellman.c b/libparc/parc/security/test/test_parc_DiffieHellman.c
new file mode 100755
index 00000000..69bc109b
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_DiffieHellman.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 <config.h>
+#include <stdio.h>
+#include <LongBow/unit-test.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include "../parc_DiffieHellman.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/algol/parc_Buffer.h>
+
+LONGBOW_TEST_RUNNER(parc_DiffieHellman)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parc_DiffieHellman)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_DiffieHellman)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellman_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellman_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellman_GenerateKeyShare);
+}
+
+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, parcDiffieHellman_Create)
+{
+ PARCDiffieHellman *dh = parcDiffieHellman_Create(PARCDiffieHellmanGroup_Secp521r1);
+ assertNotNull(dh, "Expected a non-NULL PARCDiffieHellman instance");
+ parcDiffieHellman_Release(&dh);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellman_AcquireRelease)
+{
+ PARCDiffieHellman *dh = parcDiffieHellman_Create(PARCDiffieHellmanGroup_Secp521r1);
+ parcObjectTesting_AssertAcquireReleaseContract(parcDiffieHellman_Acquire, dh);
+ parcDiffieHellman_Release(&dh);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellman_GenerateKeyShare)
+{
+ PARCDiffieHellman *dh = parcDiffieHellman_Create(PARCDiffieHellmanGroup_Secp521r1);
+ PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellman_GenerateKeyShare(dh);
+ assertNotNull(keyShare, "Expected a non-NULL PARCDiffieHellmanKeyShare instance");
+ parcDiffieHellmanKeyShare_Release(&keyShare);
+ parcDiffieHellman_Release(&dh);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_DiffieHellman);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_DiffieHellmanKeyShare.c b/libparc/parc/security/test/test_parc_DiffieHellmanKeyShare.c
new file mode 100755
index 00000000..e8a2eeca
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_DiffieHellmanKeyShare.c
@@ -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.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <LongBow/unit-test.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include "../parc_DiffieHellmanKeyShare.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/algol/parc_Buffer.h>
+
+LONGBOW_TEST_RUNNER(parc_DiffieHellmanKeyShare)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parc_DiffieHellmanKeyShare)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_DiffieHellmanKeyShare)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellmanKeyShare_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellmanKeyShare_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellmanKeyShare_SerializePublicKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellmanKeyShare_SerializeDeserializePublicKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellmanKeyShare_DeserializePublicKey_ErrorWrongGroup);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellmanKeyShare_DeserializePublicKey_ErrorInvalidEncoding);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellmanKeyShare_Combine);
+ LONGBOW_RUN_TEST_CASE(Global, parcDiffieHellmanKeyShare_Combine_Error_PublicKeyDeserializationFail);
+ LONGBOW_RUN_TEST_CASE(Global, _parcDiffieHellmanKeyShare_HashSharedSecret);
+}
+
+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, parcDiffieHellmanKeyShare_AcquireRelease)
+{
+ PARCDiffieHellmanKeyShare *dh = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ parcObjectTesting_AssertAcquireReleaseContract(parcDiffieHellmanKeyShare_Acquire, dh);
+ parcDiffieHellmanKeyShare_Release(&dh);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellmanKeyShare_Create)
+{
+ PARCDiffieHellmanKeyShare *dh = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ assertNotNull(dh, "Expected a non-NULL PARCDiffieHellmanKeyShare instance");
+ parcDiffieHellmanKeyShare_Release(&dh);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellmanKeyShare_SerializePublicKey)
+{
+ PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ assertNotNull(keyShare, "Expected a non-NULL PARCDiffieHellmanKeyShare instance");
+
+ PARCBuffer *publicKey = parcDiffieHellmanKeyShare_SerializePublicKey(keyShare);
+ assertNotNull(publicKey, "Expected the public key to be serialized to a non-NULL PARCBuffer");
+
+ const size_t sec521r1KeySize = 266;
+ assertTrue(parcBuffer_Remaining(publicKey) == sec521r1KeySize, "Expected the public key size to be %zu, got %zu", sec521r1KeySize, parcBuffer_Remaining(publicKey));
+
+ parcBuffer_Release(&publicKey);
+ parcDiffieHellmanKeyShare_Release(&keyShare);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellmanKeyShare_SerializeDeserializePublicKey)
+{
+ PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ assertNotNull(keyShare, "Expected a non-NULL PARCDiffieHellmanKeyShare instance");
+
+ PARCBuffer *publicKey = parcDiffieHellmanKeyShare_SerializePublicKey(keyShare);
+ assertNotNull(publicKey, "Expected the public key to be serialized to a non-NULL PARCBuffer");
+
+ const size_t sec521r1KeySize = 266;
+ assertTrue(parcBuffer_Remaining(publicKey) == sec521r1KeySize, "Expected the public key size to be %zu, got %zu", sec521r1KeySize, parcBuffer_Remaining(publicKey));
+
+ // Deserialize the public key to get the OpenSSL EVP_PKEY type
+ EVP_PKEY *rawPublicKey = _parcDiffieHellman_DeserializePublicKeyShare(keyShare, publicKey);
+ assertNotNull(rawPublicKey, "Expected the raw public key to be deserialized");
+
+ // Extract the public portions of the private key share and public key share
+ EC_KEY *publicEcKey = EVP_PKEY_get1_EC_KEY(rawPublicKey);
+ const EC_POINT *publicPoint = EC_KEY_get0_public_key(publicEcKey);
+
+ EC_KEY *privateEcKey = EVP_PKEY_get1_EC_KEY(keyShare->privateKey);
+ const EC_POINT *privatePoint = EC_KEY_get0_public_key(privateEcKey);
+
+ // Compare the public portions of the key shares
+ const EC_GROUP *group = EC_KEY_get0_group(publicEcKey);
+ BN_CTX *bigNumberContext = BN_CTX_new();
+ int equalResult = EC_POINT_cmp(group, publicPoint, privatePoint, bigNumberContext);
+ assertTrue(equalResult == 0, "Expected the two public points to be equal.");
+
+ BN_CTX_free(bigNumberContext);
+ EVP_PKEY_free(rawPublicKey);
+ parcBuffer_Release(&publicKey);
+ parcDiffieHellmanKeyShare_Release(&keyShare);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellmanKeyShare_DeserializePublicKey_ErrorWrongGroup)
+{
+ PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ assertNotNull(keyShare, "Expected a non-NULL PARCDiffieHellmanKeyShare instance");
+
+ PARCBuffer *publicKey = parcDiffieHellmanKeyShare_SerializePublicKey(keyShare);
+ assertNotNull(publicKey, "Expected the public key to be serialized to a non-NULL PARCBuffer");
+
+ PARCDiffieHellmanKeyShare *alternateKeyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Prime256v1);
+
+ // Deserialize the public key with a different group and hit the failure
+ EVP_PKEY *rawPublicKey = _parcDiffieHellman_DeserializePublicKeyShare(alternateKeyShare, publicKey);
+ assertNull(rawPublicKey, "Expected the raw public key to not be deserialized");
+
+ parcBuffer_Release(&publicKey);
+ parcDiffieHellmanKeyShare_Release(&keyShare);
+ parcDiffieHellmanKeyShare_Release(&alternateKeyShare);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellmanKeyShare_DeserializePublicKey_ErrorInvalidEncoding)
+{
+ PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ assertNotNull(keyShare, "Expected a non-NULL PARCDiffieHellmanKeyShare instance");
+
+ // Deserialize the public key with a different group
+ PARCBuffer *publicKey = parcBuffer_Allocate(32);
+ EVP_PKEY *rawPublicKey = _parcDiffieHellman_DeserializePublicKeyShare(keyShare, publicKey);
+ assertNull(rawPublicKey, "Expected the raw public key to not be deserialized");
+
+ parcBuffer_Release(&publicKey);
+ parcDiffieHellmanKeyShare_Release(&keyShare);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellmanKeyShare_Combine)
+{
+ PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ assertNotNull(keyShare, "Expected a non-NULL PARCDiffieHellmanKeyShare instance");
+
+ PARCBuffer *publicKey = parcDiffieHellmanKeyShare_SerializePublicKey(keyShare);
+ assertNotNull(publicKey, "Expected the public key to be serialized to a non-NULL PARCBuffer");
+
+ PARCBuffer *sharedSecret = parcDiffieHellmanKeyShare_Combine(keyShare, publicKey);
+ assertNotNull(sharedSecret, "Expected the shared secret to be non-NULL");
+
+ const size_t secretSize = 32; // = 256 / 8 bytes
+ assertTrue(parcBuffer_Remaining(sharedSecret) == secretSize, "invalid size");
+
+ parcBuffer_Release(&sharedSecret);
+ parcBuffer_Release(&publicKey);
+ parcDiffieHellmanKeyShare_Release(&keyShare);
+}
+
+LONGBOW_TEST_CASE(Global, parcDiffieHellmanKeyShare_Combine_Error_PublicKeyDeserializationFail)
+{
+ PARCDiffieHellmanKeyShare *keyShare = parcDiffieHellmanKeyShare_Create(PARCDiffieHellmanGroup_Secp521r1);
+ assertNotNull(keyShare, "Expected a non-NULL PARCDiffieHellmanKeyShare instance");
+
+ PARCBuffer *publicKey = parcBuffer_Allocate(32);
+ PARCBuffer *sharedSecret = parcDiffieHellmanKeyShare_Combine(keyShare, publicKey);
+ assertNull(sharedSecret, "Expected the shared secret to be non-NULL");
+
+ parcBuffer_Release(&publicKey);
+ parcDiffieHellmanKeyShare_Release(&keyShare);
+}
+
+LONGBOW_TEST_CASE(Global, _parcDiffieHellmanKeyShare_HashSharedSecret)
+{
+ PARCBuffer *input = parcBuffer_Allocate(1024);
+ PARCBuffer *digestValue = _parcDiffieHellmanKeyShare_HashSharedSecret(input);
+ size_t digestLength = parcBuffer_Remaining(digestValue);
+ size_t expectedLength = 32; // 256 bits for PARCCryptoHashType_SHA256
+ assertTrue(digestLength == 32, "Expected a %zu byte digest, got %zu", expectedLength, digestLength);
+
+ PARCCryptoHasher *hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBuffer(hasher, input);
+ PARCCryptoHash *digest = parcCryptoHasher_Finalize(hasher);
+
+ PARCBuffer *computedDigest = parcBuffer_Acquire(parcCryptoHash_GetDigest(digest));
+
+ parcCryptoHash_Release(&digest);
+ parcCryptoHasher_Release(&hasher);
+
+ assertTrue(parcBuffer_Equals(digestValue, computedDigest), "Expected the secret input to be hashed correctly.");
+
+ parcBuffer_Release(&input);
+ parcBuffer_Release(&digestValue);
+ parcBuffer_Release(&computedDigest);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_DiffieHellmanKeyShare);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_Identity.c b/libparc/parc/security/test/test_parc_Identity.c
new file mode 100644
index 00000000..3208efcb
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_Identity.c
@@ -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.
+ */
+
+/**
+ * @header <#Headline Name#>
+ * @abstract <#Abstract#>
+ * @discussion
+ * <#Discussion#>
+ *
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Identity.c"
+#include "../parc_IdentityFile.h"
+#include "../parc_Security.h"
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(test_parc_Identity)
+{
+ // 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_parc_Identity)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_Identity)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentity_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentity_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentity_GetFileName);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentity_GetPassWord);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentity_CreateSigner);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentity_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentity_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("Tests leak memory by %d allocations\n", outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentity_Create)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+ assertNotNull(identityFile, "Expected non-null");
+
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ assertNotNull(identity, "Expected non-null");
+ parcIdentityFile_Release(&identityFile);
+
+ parcIdentity_Release(&identity);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentity_Acquire)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+ assertNotNull(identityFile, "Expected non-null");
+
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ assertNotNull(identity, "Expected non-null");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcIdentity_Acquire, identity);
+
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentity_GetFileName)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+ assertNotNull(identityFile, "Expected non-null");
+
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ assertNotNull(identity, "Expected non-null");
+
+ assertEqualStrings(keystoreName, parcIdentity_GetFileName(identity));
+
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentity_GetPassWord)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+ assertNotNull(identityFile, "Expected non-null");
+
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ assertNotNull(identity, "Expected non-null");
+
+ assertEqualStrings(keystorePassword, parcIdentity_GetPassWord(identity));
+
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentity_CreateSigner)
+{
+ parcSecurity_Init();
+
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+ assertNotNull(identityFile, "Expected non-null");
+
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ assertNotNull(identity, "Expected non-null");
+
+ assertEqualStrings(keystorePassword, parcIdentity_GetPassWord(identity));
+
+ PARCSigner *signer = parcIdentity_CreateSigner(identity, PARCCryptoSuite_RSA_SHA256);
+
+ assertNotNull(signer, "Expected non-null");
+
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+ parcSigner_Release(&signer);
+
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentity_Equals)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFileX = parcIdentityFile_Create(keystoreName, keystorePassword);
+ PARCIdentity *x = parcIdentity_Create(identityFileX, PARCIdentityFileAsPARCIdentity);
+ PARCIdentityFile *identityFileY = parcIdentityFile_Create(keystoreName, keystorePassword);
+ PARCIdentity *y = parcIdentity_Create(identityFileY, PARCIdentityFileAsPARCIdentity);
+ PARCIdentityFile *identityFileZ = parcIdentityFile_Create(keystoreName, keystorePassword);
+ PARCIdentity *z = parcIdentity_Create(identityFileZ, PARCIdentityFileAsPARCIdentity);
+
+ PARCIdentityFile *identityFile1 = parcIdentityFile_Create("foo", keystorePassword);
+ PARCIdentityFile *identityFile2 = parcIdentityFile_Create(keystoreName, "bar");
+ PARCIdentity *u1 = parcIdentity_Create(identityFile1, PARCIdentityFileAsPARCIdentity);
+ PARCIdentity *u2 = parcIdentity_Create(identityFile2, PARCIdentityFileAsPARCIdentity);
+
+ parcObjectTesting_AssertEqualsFunction(parcIdentity_Equals, x, y, z, u1, u2);
+
+ parcIdentityFile_Release(&identityFileX);
+ parcIdentityFile_Release(&identityFileY);
+ parcIdentityFile_Release(&identityFileZ);
+ parcIdentityFile_Release(&identityFile1);
+ parcIdentityFile_Release(&identityFile2);
+
+ parcIdentity_Release(&x);
+ parcIdentity_Release(&y);
+ parcIdentity_Release(&z);
+ parcIdentity_Release(&u1);
+ parcIdentity_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentity_Display)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+ assertNotNull(identityFile, "Expected non-null");
+
+ PARCIdentity *identity = parcIdentity_Create(identityFile, PARCIdentityFileAsPARCIdentity);
+ assertNotNull(identity, "Expected non-null");
+
+ parcIdentity_Display(identity, 0);
+
+ parcIdentityFile_Release(&identityFile);
+ parcIdentity_Release(&identity);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_Identity);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_IdentityFile.c b/libparc/parc/security/test/test_parc_IdentityFile.c
new file mode 100644
index 00000000..5bcc5570
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_IdentityFile.c
@@ -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.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_IdentityFile.c"
+#include "../parc_Security.h"
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_IdentityFile)
+{
+ // 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(parc_IdentityFile)
+{
+ 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_IdentityFile)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_GetFileName);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_GetPassWord);
+ LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_CreateSigner);
+// LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_Display);
+// LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_Exists_True);
+// LONGBOW_RUN_TEST_CASE(Global, parcIdentityFile_Exists_False);
+}
+
+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, parcIdentityFile_Acquire)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+
+ assertNotNull(identityFile, "Expected non-null");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcIdentityFile_Acquire, identityFile);
+
+ parcIdentityFile_Release(&identityFile);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_Create)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+
+ assertNotNull(identityFile, "Expected non-null");
+
+ parcIdentityFile_Release(&identityFile);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_GetFileName)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+
+ assertNotNull(identityFile, "Expected non-null");
+
+ assertEqualStrings(keystoreName, parcIdentityFile_GetFileName(identityFile));
+
+ parcIdentityFile_Release(&identityFile);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_GetPassWord)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+
+ assertNotNull(identityFile, "Expected non-null");
+
+ assertEqualStrings(keystorePassword, parcIdentityFile_GetPassWord(identityFile));
+
+ parcIdentityFile_Release(&identityFile);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_Exists_True)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+
+ bool actual = parcIdentityFile_Exists(identityFile);
+
+ assertTrue(actual, "Expected %s to exist.", parcIdentityFile_GetFileName(identityFile));
+
+ parcIdentityFile_Release(&identityFile);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_Exists_False)
+{
+ const char *keystoreName = "/dev/notgoingtoexist";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+
+ bool actual = parcIdentityFile_Exists(identityFile);
+
+ assertFalse(actual, "Expected %s to not exist.", parcIdentityFile_GetFileName(identityFile));
+
+ parcIdentityFile_Release(&identityFile);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_CreateSigner)
+{
+ parcSecurity_Init();
+
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+
+ assertNotNull(identityFile, "Expected non-null");
+
+ char cwd[1024];
+ if (getcwd(cwd, sizeof(cwd)) != NULL) {
+ fprintf(stdout, "Current working dir: %s\n", cwd);
+ } else {
+ perror("getcwd() error");
+ }
+ PARCSigner *signer = parcIdentityFile_CreateSigner(identityFile, PARCCryptoSuite_RSA_SHA256);
+
+ assertNotNull(signer, "Expected non-null");
+
+ parcIdentityFile_Release(&identityFile);
+ parcSigner_Release(&signer);
+
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_Release)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+
+ assertNotNull(identityFile, "Expected non-null");
+
+ parcIdentityFile_Release(&identityFile);
+ assertNull(identityFile, "Identity File was not nulled out after Release()");
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_Equals)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *x = parcIdentityFile_Create(keystoreName, keystorePassword);
+ PARCIdentityFile *y = parcIdentityFile_Create(keystoreName, keystorePassword);
+ PARCIdentityFile *z = parcIdentityFile_Create(keystoreName, keystorePassword);
+ PARCIdentityFile *u1 = parcIdentityFile_Create("foo", keystorePassword);
+ PARCIdentityFile *u2 = parcIdentityFile_Create(keystoreName, "bar");
+
+ parcObjectTesting_AssertEqualsFunction(parcIdentityFile_Equals, x, y, z, u1, u2);
+
+ parcIdentityFile_Release(&x);
+ parcIdentityFile_Release(&y);
+ parcIdentityFile_Release(&z);
+ parcIdentityFile_Release(&u1);
+ parcIdentityFile_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(Global, parcIdentityFile_Display)
+{
+ const char *keystoreName = "test_rsa.p12";
+ const char *keystorePassword = "blueberry";
+
+ PARCIdentityFile *identityFile = parcIdentityFile_Create(keystoreName, keystorePassword);
+ assertNotNull(identityFile, "Expected non-null");
+
+ parcIdentityFile_Display(identityFile, 0);
+
+ parcIdentityFile_Release(&identityFile);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_IdentityFile);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_InMemoryVerifier.c b/libparc/parc/security/test/test_parc_InMemoryVerifier.c
new file mode 100755
index 00000000..81baebc7
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_InMemoryVerifier.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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_InMemoryVerifier.c"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/security/parc_Security.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_KeyStore.h>
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_Signer.h>
+
+#include <fcntl.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_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(parc_InMemoryVerifier)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_InMemoryVerifier)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ parcSecurity_Init();
+ LONGBOW_RUN_TEST_CASE(Global, parcInMemoryVerifier_Create);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcSecurity_Fini();
+ 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, parcInMemoryVerifier_Create)
+{
+ PARCInMemoryVerifier *verifier = parcInMemoryVerifier_Create();
+
+ assertNotNull(verifier, "Got null result from parcInMemoryVerifier_Create");
+
+ parcInMemoryVerifier_Release(&verifier);
+}
+
+// ===========
+// We use the known keys on disk for these tests
+
+typedef struct test_data {
+ PARCSigner *signer;
+ PARCInMemoryVerifier *inMemoryInterface;
+} TestData;
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_AddKeyId);
+ LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_GetCryptoHasher);
+ LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_AllowedCryptoSuite_RSA);
+
+ LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_RemoveKeyId);
+ LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature);
+ LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadHashAlg);
+ LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadSigAlg);
+ LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadHash);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ parcSecurity_Init();
+
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *signer = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256);
+ parcKeyStore_Release(&keyStore);
+
+ data->signer = parcSigner_Create(signer, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&signer);
+ assertNotNull(data->signer, "Got null result from opening openssl pkcs12 file");
+
+ data->inMemoryInterface = parcInMemoryVerifier_Create();
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcInMemoryVerifier_Release(&data->inMemoryInterface);
+ parcSigner_Release(&data->signer);
+ parcMemory_Deallocate((void **) &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, parcInMemoryVerifier_GetCryptoHasher)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCKey *key = parcSigner_CreatePublicKey(data->signer);
+ _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key);
+
+ PARCCryptoHasher *hasher = _parcInMemoryVerifier_GetCryptoHasher(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoHashType_SHA256);
+ parcKey_Release(&key);
+ assertNotNull(hasher, "Got a null hasher");
+}
+
+LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_AddKeyId)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // create the key with copies of the byte buffers
+ PARCKey *key = parcSigner_CreatePublicKey(data->signer);
+
+ _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key);
+
+ // now do something that uses the key
+ bool success = _parcInMemoryVerifier_AllowedCryptoSuite(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoSuite_RSA_SHA256);
+ parcKey_Release(&key);
+ assertTrue(success, "Should have allowed PARCCryptoSuite_RSA_SHA256 for an RSA keystore");
+}
+
+LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_AllowedCryptoSuite_RSA)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCKey *key = parcSigner_CreatePublicKey(data->signer);
+ _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key);
+
+ // now do something that uses the key
+ bool success = _parcInMemoryVerifier_AllowedCryptoSuite(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoSuite_RSA_SHA256);
+ parcKey_Release(&key);
+ assertTrue(success, "Should have allowed PARCCryptoSuite_RSA_SHA256 for an RSA keystore");
+}
+
+LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_RemoveKeyId)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+/**
+ * Verify the openssl signature using the public key and our locally computed hash
+ */
+LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // Setup the key in the verifier
+
+ PARCKey *key = parcSigner_CreatePublicKey(data->signer);
+
+ _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key);
+
+ // read the buffer to sign
+ int fd = open("test_random_bytes", O_RDONLY);
+ uint8_t buffer_to_sign[2048];
+ ssize_t read_bytes = read(fd, buffer_to_sign, 2048);
+ close(fd);
+
+ // Digest it
+ PARCCryptoHasher *digester = _parcInMemoryVerifier_GetCryptoHasher(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoHashType_SHA256);
+ assertNotNull(digester, "got null cryptohasher from inmemory verifier");
+
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes);
+ PARCCryptoHash *localHash = parcCryptoHasher_Finalize(digester);
+
+ // now read the "true" signature
+ uint8_t scratch_buffer[1024];
+ fd = open("test_random_bytes.sig", O_RDONLY);
+ read_bytes = read(fd, scratch_buffer, 1024);
+ assertTrue(read_bytes == 128,
+ "read incorrect size signature from disk: %zu", read_bytes);
+ close(fd);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer, scratch_buffer, read_bytes);
+ PARCBuffer *bb_sig = parcBufferComposer_ProduceBuffer(composer);
+
+ PARCSignature *signatureToVerify = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, bb_sig);
+ parcBuffer_Release(&bb_sig);
+ parcBufferComposer_Release(&composer);
+
+ bool success = _parcInMemoryVerifier_VerifyDigest(data->inMemoryInterface, parcKey_GetKeyId(key), localHash, PARCCryptoSuite_RSA_SHA256, signatureToVerify);
+
+ parcSignature_Release(&signatureToVerify);
+ parcCryptoHash_Release(&localHash);
+ parcKey_Release(&key);
+
+ assertTrue(success, "Could not validate signature");
+}
+
+/**
+ * Same as the "good" code above, but calculate the hash with the wrong hash algorithm. This is
+ * what would happen if the signer and the verifier did not use the same hash algorithym.
+ */
+LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadHashAlg)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool success;
+
+ // Setup the key in the verifier
+
+ PARCKey *key = parcSigner_CreatePublicKey(data->signer);
+
+ _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key);
+
+ // read the buffer to sign
+ int fd = open("test_random_bytes", O_RDONLY);
+ uint8_t buffer_to_sign[2048];
+ ssize_t read_bytes = read(fd, buffer_to_sign, 2048);
+ close(fd);
+
+ // Digest it WITH THE WRONG HASH
+ PARCCryptoHasher *digester = _parcInMemoryVerifier_GetCryptoHasher(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoHashType_SHA512);
+ assertNotNull(digester, "got null cryptohasher from inmemory verifier");
+
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes);
+ PARCCryptoHash *localHash = parcCryptoHasher_Finalize(digester);
+
+ // now read the "true" signature
+ uint8_t scratch_buffer[1024];
+ fd = open("test_random_bytes.sig", O_RDONLY);
+ read_bytes = read(fd, scratch_buffer, 1024);
+ assertTrue(read_bytes == 128, "read incorrect size signature from disk: %zu", read_bytes);
+ close(fd);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer, scratch_buffer, read_bytes);
+ PARCBuffer *bb_sig = parcBufferComposer_ProduceBuffer(composer);
+
+ PARCSignature *signatureToVerify = parcSignature_Create(PARCSigningAlgorithm_RSA,
+ PARCCryptoHashType_SHA256,
+ bb_sig);
+ parcBuffer_Release(&bb_sig);
+ parcBufferComposer_Release(&composer);
+
+ success = _parcInMemoryVerifier_VerifyDigest(data->inMemoryInterface, parcKey_GetKeyId(key), localHash, PARCCryptoSuite_RSA_SHA256, signatureToVerify);
+
+ parcSignature_Release(&signatureToVerify);
+ parcCryptoHash_Release(&localHash);
+ parcKey_Release(&key);
+
+ assertFalse(success, "Signatures should not have verified! Wrong hash types!");
+}
+
+
+/**
+ * Same as the "good" code, but tell the verifier the wrong key type. This is what would
+ * happen if the verifier somehow picked the wrong cryptosuite.
+ */
+LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadSigAlg)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // Setup the key in the verifier
+ PARCKey *key = parcSigner_CreatePublicKey(data->signer);
+
+ _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key);
+
+ // read the buffer to sign
+ int fd = open("test_random_bytes", O_RDONLY);
+ uint8_t buffer_to_sign[2048];
+ ssize_t read_bytes = read(fd, buffer_to_sign, 2048);
+ close(fd);
+
+ // Digest it
+ PARCCryptoHasher *digester = _parcInMemoryVerifier_GetCryptoHasher(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoHashType_SHA256);
+ assertNotNull(digester, "got null cryptohasher from inmemory verifier");
+
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes);
+ PARCCryptoHash *localHash = parcCryptoHasher_Finalize(digester);
+
+ // now read the "true" signature
+ uint8_t scratch_buffer[1024];
+ fd = open("test_random_bytes.sig", O_RDONLY);
+ read_bytes = read(fd, scratch_buffer, 1024);
+ assertTrue(read_bytes == 128, "read incorrect size signature from disk: %zu", read_bytes);
+ close(fd);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer, scratch_buffer, read_bytes);
+ PARCBuffer *bb_sig = parcBufferComposer_ProduceBuffer(composer);
+
+ // HERE WE TELL IT DSA, NOT RSA
+ PARCSignature *signatureToVerify = parcSignature_Create(PARCSigningAlgorithm_DSA,
+ PARCCryptoHashType_SHA256,
+ bb_sig);
+ parcBuffer_Release(&bb_sig);
+ parcBufferComposer_Release(&composer);
+
+ bool success = _parcInMemoryVerifier_VerifyDigest(data->inMemoryInterface, parcKey_GetKeyId(key), localHash, PARCCryptoSuite_RSA_SHA256, signatureToVerify);
+
+ parcSignature_Release(&signatureToVerify);
+ parcCryptoHash_Release(&localHash);
+ parcKey_Release(&key);
+
+ assertFalse(success, "Signatures should not have verified! Wrong hash types!");
+}
+
+/**
+ * THis tests the locally computed digest not matching te digest used for the signature.
+ */
+LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadHash)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // Setup the key in the verifier
+
+ PARCKey *key = parcSigner_CreatePublicKey(data->signer);
+
+ _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key);
+
+ // read the buffer to sign
+ int fd = open("test_random_bytes", O_RDONLY);
+ uint8_t buffer_to_sign[2048];
+ ssize_t read_bytes = read(fd, buffer_to_sign, 2048);
+ close(fd);
+
+ // Digest it
+ PARCCryptoHasher *digester = _parcInMemoryVerifier_GetCryptoHasher(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoHashType_SHA256);
+ assertNotNull(digester, "got null cryptohasher from inmemory verifier");
+
+ // DIGEST THE BYTES TWICE TO GIVE WRONG HASH
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes);
+ parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes);
+ PARCCryptoHash *localHash = parcCryptoHasher_Finalize(digester);
+
+ // now read the "true" signature
+ uint8_t scratch_buffer[1024];
+ fd = open("test_random_bytes.sig", O_RDONLY);
+ read_bytes = read(fd, scratch_buffer, 1024);
+ assertTrue(read_bytes == 128, "read incorrect size signature from disk: %zu", read_bytes);
+ close(fd);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer, scratch_buffer, read_bytes);
+ PARCBuffer *bb_sig = parcBufferComposer_ProduceBuffer(composer);
+
+ PARCSignature *signatureToVerify = parcSignature_Create(PARCSigningAlgorithm_RSA,
+ PARCCryptoHashType_SHA256,
+ bb_sig);
+ parcBuffer_Release(&bb_sig);
+ parcBufferComposer_Release(&composer);
+
+ bool success = _parcInMemoryVerifier_VerifyDigest(data->inMemoryInterface, parcKey_GetKeyId(key), localHash, PARCCryptoSuite_RSA_SHA256, signatureToVerify);
+
+ parcSignature_Release(&signatureToVerify);
+ parcCryptoHash_Release(&localHash);
+ parcKey_Release(&key);
+
+ assertFalse(success, "Signature verified even with wrong hash");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_InMemoryVerifier);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_InMemoryVerifierECDSA.c b/libparc/parc/security/test/test_parc_InMemoryVerifierECDSA.c
new file mode 100644
index 00000000..c007c176
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_InMemoryVerifierECDSA.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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_InMemoryVerifier.c"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/security/parc_Security.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_KeyStore.h>
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_Signer.h>
+
+#include <fcntl.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_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(parc_InMemoryVerifier)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_InMemoryVerifier)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ parcSecurity_Init();
+ LONGBOW_RUN_TEST_CASE(Global, parcInMemoryVerifier_Create);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcSecurity_Fini();
+ 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, parcInMemoryVerifier_Create)
+{
+ PARCInMemoryVerifier *verifier = parcInMemoryVerifier_Create();
+
+ assertNotNull(verifier, "Got null result from parcInMemoryVerifier_Create");
+
+ parcInMemoryVerifier_Release(&verifier);
+}
+
+// ===========
+// We use the known keys on disk for these tests
+
+typedef struct test_data {
+ PARCSigner *signer;
+ PARCInMemoryVerifier *inMemoryInterface;
+} TestData;
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_AddKeyId);
+ LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_GetCryptoHasher);
+ LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_AllowedCryptoSuite_ECDSA);
+
+ LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_RemoveKeyId);
+ LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature);
+ LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadHashAlg);
+ LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadSigAlg);
+ LONGBOW_RUN_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadHash);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ parcSecurity_Init();
+
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256);
+ parcKeyStore_Release(&keyStore);
+
+ data->signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&ecSigner);
+ assertNotNull(data->signer, "Got null result from opening openssl pkcs12 file");
+
+ data->inMemoryInterface = parcInMemoryVerifier_Create();
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcInMemoryVerifier_Release(&data->inMemoryInterface);
+ parcSigner_Release(&data->signer);
+ parcMemory_Deallocate((void **) &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, parcInMemoryVerifier_GetCryptoHasher)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCKey *key = parcSigner_CreatePublicKey(data->signer);
+ _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key);
+
+ PARCCryptoHasher *hasher = _parcInMemoryVerifier_GetCryptoHasher(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoHashType_SHA256);
+ parcKey_Release(&key);
+ assertNotNull(hasher, "Got a null hasher");
+}
+
+LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_AddKeyId)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // create the key with copies of the byte buffers
+ PARCKey *key = parcSigner_CreatePublicKey(data->signer);
+
+ _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key);
+
+ // now do something that uses the key
+ bool success = _parcInMemoryVerifier_AllowedCryptoSuite(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoSuite_ECDSA_SHA256);
+ parcKey_Release(&key);
+ assertTrue(success, "Should have allowed PARCCryptoSuite_ECDSA_SHA256 for an ECDSA keystore");
+}
+
+LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_AllowedCryptoSuite_ECDSA)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCKey *key = parcSigner_CreatePublicKey(data->signer);
+ _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key);
+
+ // now do something that uses the key
+ bool success = _parcInMemoryVerifier_AllowedCryptoSuite(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoSuite_ECDSA_SHA256);
+ parcKey_Release(&key);
+ assertTrue(success, "Should have allowed PARCCryptoSuite_ECDSA_SHA256 for an ECDSA keystore");
+}
+
+LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_RemoveKeyId)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+/**
+ * Verify the openssl signature using the public key and our locally computed hash
+ */
+LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // Setup the key in the verifier
+
+ PARCKey *key = parcSigner_CreatePublicKey(data->signer);
+
+ _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key);
+
+ // read the buffer to sign
+ int fd = open("test_random_bytes", O_RDONLY);
+ uint8_t buffer_to_sign[2048];
+ ssize_t read_bytes = read(fd, buffer_to_sign, 2048);
+ close(fd);
+
+ // Digest it
+ PARCCryptoHasher *digester = _parcInMemoryVerifier_GetCryptoHasher(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoHashType_SHA256);
+ assertNotNull(digester, "got null cryptohasher from inmemory verifier");
+
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes);
+ PARCCryptoHash *localHash = parcCryptoHasher_Finalize(digester);
+
+ // now read the "true" signature
+ uint8_t scratch_buffer[1024];
+ fd = open("test_random_bytes.sig_ec", O_RDONLY);
+ read_bytes = read(fd, scratch_buffer, 1024);
+ assertTrue(read_bytes <= 72,
+ "read incorrect size signature from disk: %zu", read_bytes);
+ close(fd);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer, scratch_buffer, read_bytes);
+ PARCBuffer *bb_sig = parcBufferComposer_ProduceBuffer(composer);
+
+ PARCSignature *signatureToVerify = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, bb_sig);
+ parcBuffer_Release(&bb_sig);
+ parcBufferComposer_Release(&composer);
+
+ bool success = _parcInMemoryVerifier_VerifyDigest(data->inMemoryInterface, parcKey_GetKeyId(key), localHash, PARCCryptoSuite_ECDSA_SHA256, signatureToVerify);
+
+ parcSignature_Release(&signatureToVerify);
+ parcCryptoHash_Release(&localHash);
+ parcKey_Release(&key);
+
+ assertTrue(success, "Could not validate signature");
+}
+
+/**
+ * Same as the "good" code above, but calculate the hash with the wrong hash algorithm. This is
+ * what would happen if the signer and the verifier did not use the same hash algorithym.
+ */
+LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadHashAlg)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ bool success;
+
+ // Setup the key in the verifier
+
+ PARCKey *key = parcSigner_CreatePublicKey(data->signer);
+
+ _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key);
+
+ // read the buffer to sign
+ int fd = open("test_random_bytes", O_RDONLY);
+ uint8_t buffer_to_sign[2048];
+ ssize_t read_bytes = read(fd, buffer_to_sign, 2048);
+ close(fd);
+
+ // Digest it WITH THE WRONG HASH
+ PARCCryptoHasher *digester = _parcInMemoryVerifier_GetCryptoHasher(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoHashType_SHA512);
+ assertNotNull(digester, "got null cryptohasher from inmemory verifier");
+
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes);
+ PARCCryptoHash *localHash = parcCryptoHasher_Finalize(digester);
+
+ // now read the "true" signature
+ uint8_t scratch_buffer[1024];
+ fd = open("test_random_bytes.sig_ec", O_RDONLY);
+ read_bytes = read(fd, scratch_buffer, 1024);
+ assertTrue(read_bytes <= 72, "read incorrect size signature from disk: %zu", read_bytes);
+ close(fd);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer, scratch_buffer, read_bytes);
+ PARCBuffer *bb_sig = parcBufferComposer_ProduceBuffer(composer);
+
+ PARCSignature *signatureToVerify = parcSignature_Create(PARCSigningAlgorithm_ECDSA,
+ PARCCryptoHashType_SHA256,
+ bb_sig);
+ parcBuffer_Release(&bb_sig);
+ parcBufferComposer_Release(&composer);
+
+ success = _parcInMemoryVerifier_VerifyDigest(data->inMemoryInterface, parcKey_GetKeyId(key), localHash, PARCCryptoSuite_ECDSA_SHA256, signatureToVerify);
+
+ parcSignature_Release(&signatureToVerify);
+ parcCryptoHash_Release(&localHash);
+ parcKey_Release(&key);
+
+ assertFalse(success, "Signatures should not have verified! Wrong hash types!");
+}
+
+
+/**
+ * Same as the "good" code, but tell the verifier the wrong key type. This is what would
+ * happen if the verifier somehow picked the wrong cryptosuite.
+ */
+LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadSigAlg)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // Setup the key in the verifier
+ PARCKey *key = parcSigner_CreatePublicKey(data->signer);
+
+ _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key);
+
+ // read the buffer to sign
+ int fd = open("test_random_bytes", O_RDONLY);
+ uint8_t buffer_to_sign[2048];
+ ssize_t read_bytes = read(fd, buffer_to_sign, 2048);
+ close(fd);
+
+ // Digest it
+ PARCCryptoHasher *digester = _parcInMemoryVerifier_GetCryptoHasher(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoHashType_SHA256);
+ assertNotNull(digester, "got null cryptohasher from inmemory verifier");
+
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes);
+ PARCCryptoHash *localHash = parcCryptoHasher_Finalize(digester);
+
+ // now read the "true" signature
+ uint8_t scratch_buffer[1024];
+ fd = open("test_random_bytes.sig_ec", O_RDONLY);
+ read_bytes = read(fd, scratch_buffer, 1024);
+ assertTrue(read_bytes <= 72, "read incorrect size signature from disk: %zu", read_bytes);
+ close(fd);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer, scratch_buffer, read_bytes);
+ PARCBuffer *bb_sig = parcBufferComposer_ProduceBuffer(composer);
+
+ // HERE WE TELL IT DSA, NOT RSA
+ PARCSignature *signatureToVerify = parcSignature_Create(PARCSigningAlgorithm_DSA,
+ PARCCryptoHashType_SHA256,
+ bb_sig);
+ parcBuffer_Release(&bb_sig);
+ parcBufferComposer_Release(&composer);
+
+ bool success = _parcInMemoryVerifier_VerifyDigest(data->inMemoryInterface, parcKey_GetKeyId(key), localHash, PARCCryptoSuite_ECDSA_SHA256, signatureToVerify);
+
+ parcSignature_Release(&signatureToVerify);
+ parcCryptoHash_Release(&localHash);
+ parcKey_Release(&key);
+
+ assertFalse(success, "Signatures should not have verified! Wrong hash types!");
+}
+
+/**
+ * THis tests the locally computed digest not matching te digest used for the signature.
+ */
+LONGBOW_TEST_CASE(Local, parcInMemoryVerifier_VerifySignature_BadHash)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ // Setup the key in the verifier
+
+ PARCKey *key = parcSigner_CreatePublicKey(data->signer);
+
+ _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key);
+
+ // read the buffer to sign
+ int fd = open("test_random_bytes", O_RDONLY);
+ uint8_t buffer_to_sign[2048];
+ ssize_t read_bytes = read(fd, buffer_to_sign, 2048);
+ close(fd);
+
+ // Digest it
+ PARCCryptoHasher *digester = _parcInMemoryVerifier_GetCryptoHasher(data->inMemoryInterface, parcKey_GetKeyId(key), PARCCryptoHashType_SHA256);
+ assertNotNull(digester, "got null cryptohasher from inmemory verifier");
+
+ // DIGEST THE BYTES TWICE TO GIVE WRONG HASH
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes);
+ parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes);
+ PARCCryptoHash *localHash = parcCryptoHasher_Finalize(digester);
+
+ // now read the "true" signature
+ uint8_t scratch_buffer[1024];
+ fd = open("test_random_bytes.sig_ec", O_RDONLY);
+ read_bytes = read(fd, scratch_buffer, 1024);
+ assertTrue(read_bytes <= 72, "read incorrect size signature from disk: %zu", read_bytes);
+ close(fd);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer, scratch_buffer, read_bytes);
+ PARCBuffer *bb_sig = parcBufferComposer_ProduceBuffer(composer);
+
+ PARCSignature *signatureToVerify = parcSignature_Create(PARCSigningAlgorithm_ECDSA,
+ PARCCryptoHashType_SHA256,
+ bb_sig);
+ parcBuffer_Release(&bb_sig);
+ parcBufferComposer_Release(&composer);
+
+ bool success = _parcInMemoryVerifier_VerifyDigest(data->inMemoryInterface, parcKey_GetKeyId(key), localHash, PARCCryptoSuite_ECDSA_SHA256, signatureToVerify);
+
+ parcSignature_Release(&signatureToVerify);
+ parcCryptoHash_Release(&localHash);
+ parcKey_Release(&key);
+
+ assertFalse(success, "Signature verified even with wrong hash");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_InMemoryVerifier);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_Key.c b/libparc/parc/security/test/test_parc_Key.c
new file mode 100755
index 00000000..d22362b0
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_Key.c
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_Key.c"
+
+#include <LongBow/unit-test.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_Key)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Errors);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(parc_Key)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Key)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_CreateFromDerEncodedPublicKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_CreateFromSymmetricKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_GetKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_GetKeyId);
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_GetSigningAlgorithm);
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcKey_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_Copy)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+ parcKey_AssertValid(key);
+
+ PARCKey *copy = parcKey_Copy(key);
+ parcKey_AssertValid(copy);
+
+ assertTrue(parcKey_Equals(key, copy), "Expected the original key instance and its copy to be equal");
+
+ parcKey_Release(&copy);
+ parcKey_Release(&key);
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_CreateFromDerEncodedPublicKey)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+
+ parcKey_AssertValid(key);
+
+ parcKey_Release(&key);
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_CreateFromSymmetricKey)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromSymmetricKey(keyid, PARCSigningAlgorithm_HMAC, bb_key);
+
+ parcKey_AssertValid(key);
+
+ parcKey_Release(&key);
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_Equals)
+{
+ PARCBuffer *bb_id_1 = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid_1 = parcKeyId_Create(bb_id_1);
+ parcBuffer_Release(&bb_id_1);
+
+ PARCBuffer *bb_id_2 = parcBuffer_Wrap("chugga chugga", 13, 0, 13);
+ PARCKeyId *keyid_2 = parcKeyId_Create(bb_id_2);
+ parcBuffer_Release(&bb_id_2);
+
+ PARCBufferComposer *composer1 = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer1, "quack quack");
+ PARCBuffer *bb_key_1 = parcBufferComposer_ProduceBuffer(composer1);
+
+ PARCKey *x = parcKey_CreateFromDerEncodedPublicKey(keyid_1, PARCSigningAlgorithm_RSA, bb_key_1);
+ PARCKey *y = parcKey_CreateFromDerEncodedPublicKey(keyid_1, PARCSigningAlgorithm_RSA, bb_key_1);
+ PARCKey *z = parcKey_CreateFromDerEncodedPublicKey(keyid_1, PARCSigningAlgorithm_RSA, bb_key_1);
+
+ PARCBufferComposer *composer2 = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer2, "mew mew");
+ PARCBuffer *bb_key_2 = parcBufferComposer_ProduceBuffer(composer2);
+ PARCKey *u1 = parcKey_CreateFromDerEncodedPublicKey(keyid_1, PARCSigningAlgorithm_RSA, bb_key_2);
+ PARCKey *u2 = parcKey_CreateFromDerEncodedPublicKey(keyid_2, PARCSigningAlgorithm_RSA, bb_key_1);
+
+ parcObjectTesting_AssertEqualsFunction(parcKey_Equals, x, y, z, u1, u2);
+
+ parcBuffer_Release(&bb_key_1);
+ parcBufferComposer_Release(&composer1);
+ parcBuffer_Release(&bb_key_2);
+ parcBufferComposer_Release(&composer2);
+ parcKeyId_Release(&keyid_1);
+ parcKeyId_Release(&keyid_2);
+
+ parcKey_Release(&x);
+ parcKey_Release(&y);
+ parcKey_Release(&z);
+ parcKey_Release(&u1);
+ parcKey_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_GetKey)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+
+ parcKey_AssertValid(key);
+
+ PARCBuffer *rawKey = parcKey_GetKey(key); // reference count is not incremented
+ assertTrue(parcBuffer_Equals(rawKey, bb_key), "Expected the raw key buffers to be equal");
+
+ parcKey_Release(&key);
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_GetKeyId)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+
+ parcKey_AssertValid(key);
+
+ PARCKeyId *rawKeyId = parcKey_GetKeyId(key); // reference count is not incremented
+ assertTrue(parcKeyId_Equals(rawKeyId, keyid), "Expected the raw KeyID buffers to be equal");
+
+ parcKey_Release(&key);
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_GetSigningAlgorithm)
+{
+ // Check for PARCSigningAlgorithm_RSA value
+ PARCBuffer *bb_id_1 = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid_1 = parcKeyId_Create(bb_id_1);
+ parcBuffer_Release(&bb_id_1);
+
+ PARCBufferComposer *composer1 = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer1, "quack quack");
+ PARCBuffer *bb_key_1 = parcBufferComposer_ProduceBuffer(composer1);
+ PARCKey *key_1 = parcKey_CreateFromDerEncodedPublicKey(keyid_1, PARCSigningAlgorithm_RSA, bb_key_1);
+
+ parcKey_AssertValid(key_1);
+
+ assertTrue((parcKey_GetSigningAlgorithm(key_1) == PARCSigningAlgorithm_RSA), "Signing Algorithms don't match");
+
+ parcBuffer_Release(&bb_key_1);
+ parcBufferComposer_Release(&composer1);
+ parcKeyId_Release(&keyid_1);
+ parcKey_Release(&key_1);
+
+ // Check for PARCSigningAlgorithm_HMAC value
+ PARCBuffer *bb_id_2 = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid_2 = parcKeyId_Create(bb_id_2);
+ parcBuffer_Release(&bb_id_2);
+
+ PARCBufferComposer *composer2 = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer2, "quack quack");
+ PARCBuffer *bb_key_2 = parcBufferComposer_ProduceBuffer(composer2);
+ PARCKey *key_2 = parcKey_CreateFromSymmetricKey(keyid_2, PARCSigningAlgorithm_HMAC, bb_key_2);
+
+ parcKey_AssertValid(key_2);
+
+ assertTrue((parcKey_GetSigningAlgorithm(key_2) == PARCSigningAlgorithm_HMAC), "Signing Algorithms don't match");
+
+ parcBuffer_Release(&bb_key_2);
+ parcBufferComposer_Release(&composer2);
+ parcKeyId_Release(&keyid_2);
+ parcKey_Release(&key_2);
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_Acquire)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+
+ parcKey_AssertValid(key);
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcKey_Acquire, key);
+ parcKey_Release(&key);
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_CASE(Global, parcKey_ToString)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+
+ char *keyString = parcKey_ToString(key);
+
+ assertNotNull(keyString, "Expected non-null key representation string");
+ assertTrue(strlen(keyString) > 0, "Expected non-null key representation string");
+
+ parcKey_Release(&key);
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_FIXTURE(Errors)
+{
+ LONGBOW_RUN_TEST_CASE(Errors, parcKey_CreateFromDerEncodedPublicKey_InvalidAlgorithm);
+ LONGBOW_RUN_TEST_CASE(Errors, parcKey_CreateFromSymmetricKey_InvalidAlgorithm);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Errors)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Errors)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcKey_CreateFromDerEncodedPublicKey_InvalidAlgorithm, .event = &LongBowTrapIllegalValue)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromDerEncodedPublicKey(keyid, PARCSigningAlgorithm_HMAC, bb_key);
+
+ assertNull(key, "This should not be reached"); //To avoid a warning
+
+ // HMAC is an illegal value for this constructor
+
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Errors, parcKey_CreateFromSymmetricKey_InvalidAlgorithm, .event = &LongBowTrapIllegalValue)
+{
+ PARCBuffer *bb_id = parcBuffer_Wrap("choo choo", 9, 0, 9);
+ PARCKeyId *keyid = parcKeyId_Create(bb_id);
+ parcBuffer_Release(&bb_id);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, "quack quack");
+ PARCBuffer *bb_key = parcBufferComposer_ProduceBuffer(composer);
+ PARCKey *key = parcKey_CreateFromSymmetricKey(keyid, PARCSigningAlgorithm_RSA, bb_key);
+
+ assertNull(key, "This should not be reached"); //To avoid a warning
+
+ // RSA/DSA are illegal values for this constructor
+
+ parcBuffer_Release(&bb_key);
+ parcBufferComposer_Release(&composer);
+ parcKeyId_Release(&keyid);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Key);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_KeyId.c b/libparc/parc/security/test/test_parc_KeyId.c
new file mode 100644
index 00000000..1b14486d
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_KeyId.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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include <parc/security/parc_KeyId.c>
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_Security.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+const char *testStr = "hello world";
+
+LONGBOW_TEST_RUNNER(test_parc_KeyId)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(test_parc_KeyId)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_KeyId)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyId_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyId_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyId_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyId_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyId_HashCode);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyId_HashCodeFromVoid);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyId_GetKeyId);
+ LONGBOW_RUN_TEST_CASE(Global, parcKeyId_ToString);
+}
+
+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, parcKeyId_Create)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *keyId = parcKeyId_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ assertNotNull(keyId, "Expected non-null");
+
+ parcKeyId_Release(&keyId);
+ assertNull(keyId, "Release did not null the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyId_Acquire)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *keyId = parcKeyId_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ assertNotNull(keyId, "Expected non-null");
+ parcObjectTesting_AssertAcquireReleaseContract(parcKeyId_Acquire, keyId);
+
+ parcKeyId_Release(&keyId);
+ assertNull(keyId, "Release did not null the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyId_Copy)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *keyId = parcKeyId_Create(buffer);
+ parcBuffer_Release(&buffer);
+
+ assertNotNull(keyId, "Expected non-null");
+
+ PARCKeyId *copy = parcKeyId_Copy(keyId);
+ parcKeyId_AssertValid(keyId);
+ parcKeyId_AssertValid(copy);
+
+ parcKeyId_Release(&keyId);
+ assertNull(keyId, "parcKeyId_Release did not null the keyId pointer.");
+
+ parcKeyId_AssertValid(copy);
+ parcKeyId_Release(&copy);
+ assertNull(keyId, "parcKeyId_Release did not null the keyId copy pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyId_Equals)
+{
+ PARCBuffer *buffer1 = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *x = parcKeyId_Create(buffer1);
+ parcBuffer_Release(&buffer1);
+
+ PARCBuffer *buffer2 = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *y = parcKeyId_Create(buffer2);
+ parcBuffer_Release(&buffer2);
+
+ PARCBuffer *buffer3 = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *z = parcKeyId_Create(buffer3);
+ parcBuffer_Release(&buffer3);
+
+ PARCBuffer *buffer4 = parcBuffer_Wrap("hello worlx", 11, 0, 11);
+ PARCKeyId *u1 = parcKeyId_Create(buffer4);
+ parcBuffer_Release(&buffer4);
+
+ parcObjectTesting_AssertEqualsFunction(parcKeyId_Equals, x, y, z, u1);
+
+ parcKeyId_Release(&x);
+ parcKeyId_Release(&y);
+ parcKeyId_Release(&z);
+ parcKeyId_Release(&u1);
+
+ assertNull(x, "Release did not null the pointer.");
+ assertNull(y, "Release did not null the pointer.");
+ assertNull(z, "Release did not null the pointer.");
+ assertNull(u1, "Release did not null the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyId_HashCode)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *keyId = parcKeyId_Create(buffer);
+
+ assertNotNull(keyId, "Expected non-null");
+
+ assertTrue(parcKeyId_HashCode(keyId) == parcBuffer_HashCode(buffer), "Expected hash codes to be equal");
+
+ parcBuffer_Release(&buffer);
+ parcKeyId_Release(&keyId);
+ assertNull(keyId, "Release did not null the pointer.");
+}
+
+
+LONGBOW_TEST_CASE(Global, parcKeyId_HashCodeFromVoid)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *keyId = parcKeyId_Create(buffer);
+
+ assertNotNull(keyId, "Expected non-null");
+
+ assertTrue(parcKeyId_HashCodeFromVoid((void *) keyId) == parcBuffer_HashCode(buffer), "Expected hash codes to be equal");
+
+ parcBuffer_Release(&buffer);
+ parcKeyId_Release(&keyId);
+ assertNull(keyId, "Release did not null the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyId_GetKeyId)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *keyId = parcKeyId_Create(buffer);
+
+ assertNotNull(keyId, "Expected non-null");
+
+ PARCBuffer *rawBuffer = (PARCBuffer *) parcKeyId_GetKeyId(keyId);
+ assertTrue(parcBuffer_Equals(rawBuffer, buffer), "Expected the raw key buffers to be equal");
+
+ parcBuffer_Release(&buffer);
+ parcKeyId_Release(&keyId);
+ assertNull(keyId, "Release did not null the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, parcKeyId_ToString)
+{
+ PARCBuffer *buffer = parcBuffer_Wrap((void *) testStr, strlen(testStr), 0, strlen(testStr));
+ PARCKeyId *keyId = parcKeyId_Create(buffer);
+
+ parcBuffer_Release(&buffer);
+
+ assertNotNull(keyId, "Expected non-null");
+
+ char *string = parcKeyId_ToString(keyId);
+ printf("Hello: %s\n", string);
+ parcMemory_Deallocate((void **) &string);
+
+ parcKeyId_Release(&keyId);
+ assertNull(keyId, "Release did not null the pointer.");
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_KeyId);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_KeyStore.c b/libparc/parc/security/test/test_parc_KeyStore.c
new file mode 100755
index 00000000..b48099cb
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_KeyStore.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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_KeyStore.c"
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_KeyStore)
+{
+ // 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(parc_KeyStore)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_KeyStore)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+// LONGBOW_RUN_TEST_CASE(Global, parcKeyStore_Acquire);
+// LONGBOW_RUN_TEST_CASE(Global, parcKeyStore_CreateFile);
+// LONGBOW_RUN_TEST_CASE(Global, parcKeyStore_GetFileName);
+// LONGBOW_RUN_TEST_CASE(Global, parcKeyStore_GetPassWord);
+// LONGBOW_RUN_TEST_CASE(Global, parcKeyStore_Release);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+//LONGBOW_TEST_CASE(Global, parcKeyStore_Acquire)
+//{
+// const char *keystoreName = "test_rsa.p12";
+// const char *keystorePassword = "blueberry";
+//
+// PARCKeyStore *keyStoreFile = parcKeyStore_CreateFile(keystoreName, keystorePassword);
+//
+// assertNotNull(keyStoreFile, "Expected non-null");
+//
+// parcObjectTesting_AssertAcquireReleaseContract(parcKeyStore_Acquire, keyStoreFile);
+//
+// parcKeyStore_Release(&keyStoreFile);
+//}
+//
+//LONGBOW_TEST_CASE(Global, parcKeyStore_CreateFile)
+//{
+// const char *keystoreName = "test_rsa.p12";
+// const char *keystorePassword = "blueberry";
+//
+// PARCKeyStore *keyStoreFile = parcKeyStore_CreateFile(keystoreName, keystorePassword);
+//
+// assertNotNull(keyStoreFile, "Expected non-null");
+//
+// parcKeyStore_Release(&keyStoreFile);
+//}
+//
+//LONGBOW_TEST_CASE(Global, parcKeyStore_GetFileName)
+//{
+// const char *keystoreName = "test_rsa.p12";
+// const char *keystorePassword = "blueberry";
+//
+// PARCKeyStore *keyStoreFile = parcKeyStore_CreateFile(keystoreName, keystorePassword);
+//
+// assertNotNull(keyStoreFile, "Expected non-null");
+//
+// assertEqualStrings(keystoreName, parcKeyStore_GetFileName(keyStoreFile));
+//
+// parcKeyStore_Release(&keyStoreFile);
+//}
+//
+//LONGBOW_TEST_CASE(Global, parcKeyStore_GetPassWord)
+//{
+// const char *keystoreName = "test_rsa.p12";
+// const char *keystorePassword = "blueberry";
+//
+// PARCKeyStore *keyStoreFile = parcKeyStore_CreateFile(keystoreName, keystorePassword);
+//
+// assertNotNull(keyStoreFile, "Expected non-null");
+//
+// assertEqualStrings(keystorePassword, parcKeyStore_GetPassWord(keyStoreFile));
+//
+// parcKeyStore_Release(&keyStoreFile);
+//}
+//
+//LONGBOW_TEST_CASE(Global, parcKeyStore_Release)
+//{
+// const char *keystoreName = "test_rsa.p12";
+// const char *keystorePassword = "blueberry";
+//
+// PARCKeyStore *keyStoreFile = parcKeyStore_CreateFile(keystoreName, keystorePassword);
+//
+// assertNotNull(keyStoreFile, "Expected non-null");
+//
+// parcKeyStore_Release(&keyStoreFile);
+// assertNull(keyStoreFile, "Key store File was not nulled out after Release()");
+//}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_KeyStore);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_Pkcs12KeyStore.c b/libparc/parc/security/test/test_parc_Pkcs12KeyStore.c
new file mode 100755
index 00000000..17a5b60f
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_Pkcs12KeyStore.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 <config.h>
+
+#include <LongBow/testing.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Pkcs12KeyStore.c"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_PublicKeySigner.h>
+
+const char *filename = "/tmp/filekeystore.p12";
+
+LONGBOW_TEST_RUNNER(ccnx_FileKeystore)
+{
+ // 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(openssl_commandline);
+ LONGBOW_RUN_TEST_FIXTURE(ccnx_internal);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_FileKeystore)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_FileKeystore)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcPkcs12KeyStore_Open);
+ LONGBOW_RUN_TEST_CASE(Global, parcPkcs12KeyStore_badpass);
+ LONGBOW_RUN_TEST_CASE(Global, parcPkcs12KeyStore_CreateAndOpen);
+ LONGBOW_RUN_TEST_CASE(Global, parcPkcs12KeyStore_CreateFile_Fail);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ unlink(filename);
+ 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(Global, parcPkcs12KeyStore_Open)
+{
+ // open our test p12 file created with openssl
+ parcSecurity_Init();
+
+ PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open("test_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+
+ assertNotNull(keyStore, "Got null result from opening openssl pkcs12 file");
+
+ parcPkcs12KeyStore_Release(&keyStore);
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_CASE(Global, parcPkcs12KeyStore_badpass)
+{
+ // open our test p12 file created with openssl
+
+ fprintf(stderr, "The next openssl error is expected, we're using the wrong password\n");
+ PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open("test_rsa.p12", "orange", PARCCryptoHashType_SHA256);
+
+ assertNull(keyStore, "Got null result from opening openssl pkcs12 file");
+}
+
+LONGBOW_TEST_CASE(Global, parcPkcs12KeyStore_CreateAndOpen)
+{
+ // create a file and open it
+ const char *filename = "/tmp/parcPkcs12KeyStore_CreateAndOpen.p12";
+ const char *password = "12345";
+ const char *subject = "alice";
+ bool result;
+
+ result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_RSA, 1024, 32);
+ assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File");
+
+ PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+
+ assertNotNull(keyStore, "Got null result from opening openssl pkcs12 file");
+
+ parcPkcs12KeyStore_Release(&keyStore);
+ unlink(filename);
+}
+
+LONGBOW_TEST_CASE(Global, parcPkcs12KeyStore_CreateFile_Fail)
+{
+ // create a file and open it
+ const char *filename = "/tmp/parcPkcs12KeyStore_CreateAndOpen.p12";
+ const char *password = "12345";
+ const char *subject = "alice";
+ bool result;
+
+ result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_RSA, -1, 32);
+ assertFalse(result, "Expected false result from parcPkcs12KeyStore_CreateFile()");
+
+ unlink(filename);
+}
+
+
+// =====================================================
+// These are tests based on internally-generated pkcs12
+
+LONGBOW_TEST_FIXTURE(ccnx_internal)
+{
+ LONGBOW_RUN_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetCertificateDigest);
+ LONGBOW_RUN_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetPublicKeyDigest);
+ LONGBOW_RUN_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetEncodedCertificate);
+ LONGBOW_RUN_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetEncodedPublicKey);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(ccnx_internal)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(ccnx_internal)
+{
+ unlink(filename);
+ 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(ccnx_internal, parcPkcs12KeyStore_GetCertificateDigest)
+{
+ // create a file and open it
+ const char *password = "12345";
+ const char *subject = "alice";
+ bool result;
+
+ result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_RSA, 1024, 32);
+ assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File");
+
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+ assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file");
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCCryptoHash *cert_digest = parcKeyStore_GetCertificateDigest(keyStore);
+ assertNotNull(cert_digest, "got null public key digest for external pkcs12");
+
+ size_t bb_length = parcBuffer_Remaining(parcCryptoHash_GetDigest(cert_digest));
+ assertTrue(bb_length == SHA256_DIGEST_LENGTH,
+ "Incorrect digest length returned from GetPublicKeyDigest: %zu", bb_length);
+
+ parcKeyStore_Release(&keyStore);
+ parcCryptoHash_Release(&cert_digest);
+}
+
+/**
+ * Use a ccnx-generated pkcs12 file
+ */
+LONGBOW_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetPublicKeyDigest)
+{
+ // create a file and open it
+ const char *password = "12345";
+ const char *subject = "alice";
+ bool result;
+
+ result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_RSA, 1024, 32);
+ assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File");
+
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+ assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file");
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCCryptoHash *pkd = parcKeyStore_GetVerifierKeyDigest(keyStore);
+ assertNotNull(pkd, "got null public key digest for external pkcs12");
+
+ size_t bb_length = parcBuffer_Remaining(parcCryptoHash_GetDigest(pkd));
+ assertTrue(bb_length == SHA256_DIGEST_LENGTH, "Incorrect digest length returned from GetPublicKeyDigest: %zu", bb_length);
+
+ parcKeyStore_Release(&keyStore);
+ parcCryptoHash_Release(&pkd);
+}
+
+
+LONGBOW_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetEncodedCertificate)
+{
+ // create a file and open it
+ const char *password = "12345";
+ const char *subject = "alice";
+ bool result;
+
+ result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_RSA, 1024, 32);
+ assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File");
+
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+ assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file");
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCBuffer *certificate_der = parcKeyStore_GetDEREncodedCertificate(keyStore);
+ assertNotNull(certificate_der, "got null public key digest for external pkcs12");
+
+ // 557 (64-bit) and 553 (32-bit) are pre-etermined sizes of how big a DER encoded
+ // certificate with a 1024-bit key should be
+ size_t expectedMinimumLength = 545;
+ size_t expectedMaximumLength = 560;
+ size_t bb_length = parcBuffer_Remaining(certificate_der);
+ assertTrue(expectedMinimumLength <= bb_length && bb_length <= expectedMaximumLength,
+ "Digest unexpected size: got %zu expected %zu - %zu", bb_length, expectedMinimumLength, expectedMaximumLength);
+
+ parcKeyStore_Release(&keyStore);
+ parcBuffer_Release(&certificate_der);
+}
+
+LONGBOW_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetEncodedPublicKey)
+{
+ // create a file and open it
+ const char *password = "12345";
+ const char *subject = "alice";
+ bool result;
+
+ result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_RSA, 1024, 32);
+ assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File");
+
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+ assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file");
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCBuffer *pubkey_der = parcKeyStore_GetDEREncodedPublicKey(keyStore);
+ assertNotNull(pubkey_der, "got null public key digest for external pkcs12");
+
+ size_t bb_length = parcBuffer_Remaining(pubkey_der);
+ assertTrue(bb_length == 162, "Incorrect digest length returned from GetPublicKeyDigest: %zu", bb_length);
+
+ parcKeyStore_Release(&keyStore);
+ parcBuffer_Release(&pubkey_der);
+}
+
+// =====================================================
+// These are tests based on pre-generated material from the openssl command line
+
+LONGBOW_TEST_FIXTURE(openssl_commandline)
+{
+ LONGBOW_RUN_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetCertificateDigest);
+ LONGBOW_RUN_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetPublicKeyDigest);
+ LONGBOW_RUN_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetEncodedCertificate);
+ LONGBOW_RUN_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetEncodedPublicKey);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(openssl_commandline)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(openssl_commandline)
+{
+ unlink(filename);
+ 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;
+}
+
+/**
+ * read in the openssl command-line generated pkcs12 file
+ */
+LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetPublicKeyDigest)
+{
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *PublicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256);
+ parcKeyStore_Release(&keyStore);
+ PARCSigner *signer = parcSigner_Create(PublicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&PublicKeySigner);
+
+ assertNotNull(signer, "parcPkcs12KeyStore_Open(\"test_rsa.p12\", \"blueberry\", PARCCryptoHashType_SHA256) returned NULL");
+
+ PARCCryptoHash *pkd = parcKeyStore_GetVerifierKeyDigest(parcSigner_GetKeyStore(signer));
+ assertNotNull(pkd, "got null public key digest for external pkcs12");
+
+ // read in the "truth" from the command line utilities
+
+ int fd = open("test_rsa_pub_sha256.bin", O_RDONLY);
+ uint8_t true_digest[SHA256_DIGEST_LENGTH];
+ ssize_t read_bytes = read(fd, true_digest, SHA256_DIGEST_LENGTH);
+ close(fd);
+
+ assertTrue(read_bytes == SHA256_DIGEST_LENGTH, "could not read %d byte digest from test_rsa_pub_sha256.bin", SHA256_DIGEST_LENGTH);
+
+ PARCBuffer *digest = parcCryptoHash_GetDigest(pkd);
+ const uint8_t *bb_buffer = parcByteArray_Array(parcBuffer_Array(digest));
+ size_t bb_length = parcBuffer_Remaining(digest);
+ assertTrue(bb_length == SHA256_DIGEST_LENGTH,
+ "Incorrect digest length returned from GetPublicKeyDigest: %zu", bb_length);
+
+ assertTrue(memcmp(bb_buffer, true_digest, SHA256_DIGEST_LENGTH) == 0, "digests did not match");
+
+
+ parcSigner_Release(&signer);
+ parcCryptoHash_Release(&pkd);
+}
+
+/**
+ * Get the certificate digest from the openssl command line pkcs12
+ */
+LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetCertificateDigest)
+{
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *PublicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256);
+ parcKeyStore_Release(&keyStore);
+ PARCSigner *signer = parcSigner_Create(PublicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&PublicKeySigner);
+
+ assertNotNull(signer, "Got null result from opening openssl pkcs12 file");
+
+ PARCCryptoHash *cert_digest = parcKeyStore_GetCertificateDigest(parcSigner_GetKeyStore(signer));
+ assertNotNull(cert_digest, "got null public key digest for external pkcs12");
+
+ // read in the "truth" from the command line utilities
+
+ int fd = open("test_rsa_crt_sha256.bin", O_RDONLY);
+ uint8_t true_digest[SHA256_DIGEST_LENGTH];
+ ssize_t read_bytes = read(fd, true_digest, SHA256_DIGEST_LENGTH);
+ close(fd);
+
+ assertTrue(read_bytes == SHA256_DIGEST_LENGTH, "could not read %d byte digest from test_rsa_pub_sha256.bin", SHA256_DIGEST_LENGTH);
+
+ const uint8_t *bb_buffer = parcByteArray_Array(parcBuffer_Array(parcCryptoHash_GetDigest(cert_digest)));
+ size_t bb_length = parcBuffer_Remaining(parcCryptoHash_GetDigest(cert_digest));
+ assertTrue(bb_length == SHA256_DIGEST_LENGTH,
+ "Incorrect digest length returned from GetCertificateDigest: %zu", bb_length);
+
+ assertTrue(memcmp(bb_buffer, true_digest, SHA256_DIGEST_LENGTH) == 0, "digests did not match");
+
+ parcSigner_Release(&signer);
+ parcCryptoHash_Release(&cert_digest);
+}
+
+LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetEncodedCertificate)
+{
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *PublicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256);
+ parcKeyStore_Release(&keyStore);
+ PARCSigner *signer = parcSigner_Create(PublicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&PublicKeySigner);
+
+ assertNotNull(signer, "Got null result from opening openssl pkcs12 file");
+
+ PARCBuffer *certificate_der = parcKeyStore_GetDEREncodedCertificate(parcSigner_GetKeyStore(signer));
+ assertNotNull(certificate_der, "got null der certificate for external pkcs12");
+
+ // read in the "truth" from the command line utilities
+
+ int fd = open("test_rsa_crt.der", O_RDONLY);
+ uint8_t true_der[1024];
+ ssize_t read_bytes = read(fd, true_der, 1024);
+ close(fd);
+
+ assertTrue(read_bytes == 517,
+ "could not read %d byte digest from test_rsa_pub_sha256.bin", 517);
+
+ const uint8_t *bb_buffer = parcByteArray_Array(parcBuffer_Array(certificate_der));
+ size_t bb_length = parcBuffer_Remaining(certificate_der);
+ assertTrue(bb_length == read_bytes,
+ "Incorrect digest length returned from GetCertificateDigest: %zu", bb_length);
+
+ assertTrue(memcmp(bb_buffer, true_der, read_bytes) == 0, "digests did not match");
+
+ parcSigner_Release(&signer);
+ parcBuffer_Release(&certificate_der);
+}
+
+/**
+ * Gets the DER encoded public key
+ */
+LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetEncodedPublicKey)
+{
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *PublicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256);
+ parcKeyStore_Release(&keyStore);
+ PARCSigner *signer = parcSigner_Create(PublicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&PublicKeySigner);
+
+ assertNotNull(signer, "Got null result from opening openssl pkcs12 file");
+
+ PARCBuffer *pubkey_der = parcKeyStore_GetDEREncodedPublicKey(parcSigner_GetKeyStore(signer));
+ assertNotNull(pubkey_der, "got null public key der for external pkcs12");
+
+ // read in the "truth" from the command line utilities
+
+ int fd = open("test_rsa_pub.der", O_RDONLY);
+ uint8_t true_der[1024];
+ ssize_t read_bytes = read(fd, true_der, 1024);
+ close(fd);
+
+ assertTrue(read_bytes == 162, "could not read %d byte digest from test_rsa_pub_sha256.bin", 162);
+
+ const uint8_t *bb_buffer = parcByteArray_Array(parcBuffer_Array(pubkey_der));
+ size_t bb_length = parcBuffer_Remaining(pubkey_der);
+ assertTrue(bb_length == read_bytes, "Incorrect digest length returned from GetCertificateDigest: %zu", bb_length);
+ assertTrue(memcmp(bb_buffer, true_der, read_bytes) == 0, "digests did not match");
+
+ parcSigner_Release(&signer);
+ parcBuffer_Release(&pubkey_der);
+}
+
+LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_VerifySignature_Cert)
+{
+ testUnimplemented("Not Implemented");
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_FileKeystore);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_Pkcs12KeyStoreECDSA.c b/libparc/parc/security/test/test_parc_Pkcs12KeyStoreECDSA.c
new file mode 100644
index 00000000..f6b19593
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_Pkcs12KeyStoreECDSA.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 <config.h>
+
+#include <LongBow/testing.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Pkcs12KeyStore.c"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_PublicKeySigner.h>
+
+const char *filename = "/tmp/filekeystore.p12";
+
+LONGBOW_TEST_RUNNER(ccnx_FileKeystore)
+{
+ // 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(openssl_commandline);
+ LONGBOW_RUN_TEST_FIXTURE(ccnx_internal);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(ccnx_FileKeystore)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(ccnx_FileKeystore)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcPkcs12KeyStore_Open);
+ LONGBOW_RUN_TEST_CASE(Global, parcPkcs12KeyStore_badpass);
+ LONGBOW_RUN_TEST_CASE(Global, parcPkcs12KeyStore_CreateAndOpen);
+ LONGBOW_RUN_TEST_CASE(Global, parcPkcs12KeyStore_CreateFile_Fail);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ unlink(filename);
+ 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(Global, parcPkcs12KeyStore_Open)
+{
+ // open our test p12 file created with openssl
+ parcSecurity_Init();
+
+ PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256);
+
+ assertNotNull(keyStore, "Got null result from opening openssl pkcs12 file");
+
+ parcPkcs12KeyStore_Release(&keyStore);
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_CASE(Global, parcPkcs12KeyStore_badpass)
+{
+ // open our test p12 file created with openssl
+
+ fprintf(stderr, "The next openssl error is expected, we're using the wrong password\n");
+ PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open("test_ec.p12", "orange", PARCCryptoHashType_SHA256);
+
+ assertNull(keyStore, "Got null result from opening openssl pkcs12 file");
+}
+
+LONGBOW_TEST_CASE(Global, parcPkcs12KeyStore_CreateAndOpen)
+{
+ // create a file and open it
+ const char *filename = "/tmp/parcPkcs12KeyStore_CreateAndOpen.p12";
+ const char *password = "12345";
+ const char *subject = "alice";
+ bool result;
+
+ result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_ECDSA, 256, 32);
+ assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File");
+
+ PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+
+ assertNotNull(keyStore, "Got null result from opening openssl pkcs12 file");
+
+ parcPkcs12KeyStore_Release(&keyStore);
+ unlink(filename);
+}
+
+LONGBOW_TEST_CASE(Global, parcPkcs12KeyStore_CreateFile_Fail)
+{
+ // create a file and open it
+ const char *filename = "/tmp/parcPkcs12KeyStore_CreateAndOpen.p12";
+ const char *password = "12345";
+ const char *subject = "alice";
+ bool result;
+
+ result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_ECDSA, -1, 32);
+ assertFalse(result, "Expected false result from parcPkcs12KeyStore_CreateFile()");
+
+ unlink(filename);
+}
+
+
+// =====================================================
+// These are tests based on internally-generated pkcs12
+
+LONGBOW_TEST_FIXTURE(ccnx_internal)
+{
+ LONGBOW_RUN_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetCertificateDigest);
+ LONGBOW_RUN_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetPublicKeyDigest);
+ LONGBOW_RUN_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetEncodedCertificate);
+ LONGBOW_RUN_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetEncodedPublicKey);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(ccnx_internal)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(ccnx_internal)
+{
+ unlink(filename);
+ 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(ccnx_internal, parcPkcs12KeyStore_GetCertificateDigest)
+{
+ // create a file and open it
+ const char *password = "12345";
+ const char *subject = "alice";
+ bool result;
+
+ result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_ECDSA, 256, 32);
+ assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File");
+
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+ assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file");
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCCryptoHash *cert_digest = parcKeyStore_GetCertificateDigest(keyStore);
+ assertNotNull(cert_digest, "got null public key digest for external pkcs12");
+
+ size_t bb_length = parcBuffer_Remaining(parcCryptoHash_GetDigest(cert_digest));
+ assertTrue(bb_length == SHA256_DIGEST_LENGTH,
+ "Incorrect digest length returned from GetPublicKeyDigest: %zu", bb_length);
+
+ parcKeyStore_Release(&keyStore);
+ parcCryptoHash_Release(&cert_digest);
+}
+
+/**
+ * Use a ccnx-generated pkcs12 file
+ */
+LONGBOW_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetPublicKeyDigest)
+{
+ // create a file and open it
+ const char *password = "12345";
+ const char *subject = "alice";
+ bool result;
+
+ result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_ECDSA, 256, 32);
+ assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File");
+
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+ assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file");
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCCryptoHash *pkd = parcKeyStore_GetVerifierKeyDigest(keyStore);
+ assertNotNull(pkd, "got null public key digest for external pkcs12");
+
+ size_t bb_length = parcBuffer_Remaining(parcCryptoHash_GetDigest(pkd));
+ assertTrue(bb_length == SHA256_DIGEST_LENGTH, "Incorrect digest length returned from GetPublicKeyDigest: %zu", bb_length);
+
+ parcKeyStore_Release(&keyStore);
+ parcCryptoHash_Release(&pkd);
+}
+
+
+LONGBOW_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetEncodedCertificate)
+{
+ // create a file and open it
+ const char *password = "12345";
+ const char *subject = "alice";
+ bool result;
+
+ result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_ECDSA, 256, 32);
+ assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File");
+
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+ assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file");
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCBuffer *certificate_der = parcKeyStore_GetDEREncodedCertificate(keyStore);
+ assertNotNull(certificate_der, "got null public key digest for external pkcs12");
+
+ // 557 (64-bit) and 553 (32-bit) are pre-etermined sizes of how big a DER encoded
+ // certificate with a 1024-bit key should be
+ size_t expectedMinimumLength = 400;
+ size_t expectedMaximumLength = 560;
+ size_t bb_length = parcBuffer_Remaining(certificate_der);
+ assertTrue(expectedMinimumLength <= bb_length && bb_length <= expectedMaximumLength,
+ "Digest unexpected size: got %zu expected %zu - %zu", bb_length, expectedMinimumLength, expectedMaximumLength);
+
+ parcKeyStore_Release(&keyStore);
+ parcBuffer_Release(&certificate_der);
+}
+
+LONGBOW_TEST_CASE(ccnx_internal, parcPkcs12KeyStore_GetEncodedPublicKey)
+{
+ // create a file and open it
+ const char *password = "12345";
+ const char *subject = "alice";
+ bool result;
+
+ result = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_ECDSA, 256, 32);
+ assertTrue(result, "got error from parcPkcs12KeyStore_CreatePkcs12File");
+
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+ assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file");
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCBuffer *pubkey_der = parcKeyStore_GetDEREncodedPublicKey(keyStore);
+ assertNotNull(pubkey_der, "got null public key digest for external pkcs12");
+
+ size_t bb_length = parcBuffer_Remaining(pubkey_der);
+ //assertTrue(bb_length == 162, "Incorrect digest length returned from GetPublicKeyDigest: %zu", bb_length);
+
+ parcKeyStore_Release(&keyStore);
+ parcBuffer_Release(&pubkey_der);
+}
+
+// =====================================================
+// These are tests based on pre-generated material from the openssl command line
+
+LONGBOW_TEST_FIXTURE(openssl_commandline)
+{
+ LONGBOW_RUN_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetCertificateDigest);
+ LONGBOW_RUN_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetPublicKeyDigest);
+ LONGBOW_RUN_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetEncodedCertificate);
+ LONGBOW_RUN_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetEncodedPublicKey);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(openssl_commandline)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(openssl_commandline)
+{
+ unlink(filename);
+ 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;
+}
+
+/**
+ * read in the openssl command-line generated pkcs12 file
+ */
+LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetPublicKeyDigest)
+{
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256);
+ parcKeyStore_Release(&keyStore);
+ PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&ecSigner);
+
+ assertNotNull(signer, "parcPkcs12KeyStore_Open(\"test_ec.p12\", \"blueberry\", PARCCryptoHashType_SHA256) returned NULL");
+
+ PARCCryptoHash *pkd = parcKeyStore_GetVerifierKeyDigest(parcSigner_GetKeyStore(signer));
+ assertNotNull(pkd, "got null public key digest for external pkcs12");
+
+ // read in the "truth" from the command line utilities
+
+ int fd = open("test_ec_pub_sha256.bin", O_RDONLY);
+ uint8_t true_digest[SHA256_DIGEST_LENGTH];
+ ssize_t read_bytes = read(fd, true_digest, SHA256_DIGEST_LENGTH);
+ close(fd);
+
+ assertTrue(read_bytes == SHA256_DIGEST_LENGTH, "could not read %d byte digest from test_ec_pub_sha256.bin", SHA256_DIGEST_LENGTH);
+
+ PARCBuffer *digest = parcCryptoHash_GetDigest(pkd);
+ const uint8_t *bb_buffer = parcByteArray_Array(parcBuffer_Array(digest));
+ size_t bb_length = parcBuffer_Remaining(digest);
+ assertTrue(bb_length == SHA256_DIGEST_LENGTH,
+ "Incorrect digest length returned from GetPublicKeyDigest: %zu", bb_length);
+
+ assertTrue(memcmp(bb_buffer, true_digest, SHA256_DIGEST_LENGTH) == 0, "digests did not match");
+
+
+ parcSigner_Release(&signer);
+ parcCryptoHash_Release(&pkd);
+}
+
+/**
+ * Get the certificate digest from the openssl command line pkcs12
+ */
+LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetCertificateDigest)
+{
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256);
+ parcKeyStore_Release(&keyStore);
+ PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&ecSigner);
+
+ assertNotNull(signer, "Got null result from opening openssl pkcs12 file");
+
+ PARCCryptoHash *cert_digest = parcKeyStore_GetCertificateDigest(parcSigner_GetKeyStore(signer));
+ assertNotNull(cert_digest, "got null public key digest for external pkcs12");
+
+ // read in the "truth" from the command line utilities
+
+ int fd = open("test_ec_crt_sha256.bin", O_RDONLY);
+ uint8_t true_digest[SHA256_DIGEST_LENGTH];
+ ssize_t read_bytes = read(fd, true_digest, SHA256_DIGEST_LENGTH);
+ close(fd);
+
+ assertTrue(read_bytes == SHA256_DIGEST_LENGTH, "could not read %d byte digest from test_ec_pub_sha256.bin", SHA256_DIGEST_LENGTH);
+
+ const uint8_t *bb_buffer = parcByteArray_Array(parcBuffer_Array(parcCryptoHash_GetDigest(cert_digest)));
+ size_t bb_length = parcBuffer_Remaining(parcCryptoHash_GetDigest(cert_digest));
+ assertTrue(bb_length == SHA256_DIGEST_LENGTH,
+ "Incorrect digest length returned from GetCertificateDigest: %zu", bb_length);
+
+ assertTrue(memcmp(bb_buffer, true_digest, SHA256_DIGEST_LENGTH) == 0, "digests did not match");
+
+ parcSigner_Release(&signer);
+ parcCryptoHash_Release(&cert_digest);
+}
+
+LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetEncodedCertificate)
+{
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256);
+ parcKeyStore_Release(&keyStore);
+ PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&ecSigner);
+
+ assertNotNull(signer, "Got null result from opening openssl pkcs12 file");
+
+ PARCBuffer *certificate_der = parcKeyStore_GetDEREncodedCertificate(parcSigner_GetKeyStore(signer));
+ assertNotNull(certificate_der, "got null der certificate for external pkcs12");
+
+ // read in the "truth" from the command line utilities
+
+ int fd = open("test_ec_crt.der", O_RDONLY);
+ uint8_t true_der[1024];
+ ssize_t read_bytes = read(fd, true_der, 1024);
+ close(fd);
+
+ // assertTrue(read_bytes == 517,
+ // "could not read %d byte digest from test_ec_pub_sha256.bin", 517);
+
+ const uint8_t *bb_buffer = parcByteArray_Array(parcBuffer_Array(certificate_der));
+ size_t bb_length = parcBuffer_Remaining(certificate_der);
+ assertTrue(bb_length == read_bytes,
+ "Incorrect digest length returned from GetCertificateDigest: %zu", bb_length);
+
+ assertTrue(memcmp(bb_buffer, true_der, read_bytes) == 0, "digests did not match");
+
+ parcSigner_Release(&signer);
+ parcBuffer_Release(&certificate_der);
+}
+
+/**
+ * Gets the DER encoded public key
+ */
+LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_GetEncodedPublicKey)
+{
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256);
+ parcKeyStore_Release(&keyStore);
+ PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&ecSigner);
+
+ assertNotNull(signer, "Got null result from opening openssl pkcs12 file");
+
+ PARCBuffer *pubkey_der = parcKeyStore_GetDEREncodedPublicKey(parcSigner_GetKeyStore(signer));
+ assertNotNull(pubkey_der, "got null public key der for external pkcs12");
+
+ // read in the "truth" from the command line utilities
+
+ int fd = open("test_ec_pub.der", O_RDONLY);
+ uint8_t true_der[1024];
+ ssize_t read_bytes = read(fd, true_der, 1024);
+ close(fd);
+
+ //assertTrue(read_bytes == 162, "could not read %d byte digest from test_ec_pub_sha256.bin", 162);
+
+ const uint8_t *bb_buffer = parcByteArray_Array(parcBuffer_Array(pubkey_der));
+ size_t bb_length = parcBuffer_Remaining(pubkey_der);
+ assertTrue(bb_length == read_bytes, "Incorrect digest length returned from GetCertificateDigest: %zu", bb_length);
+ assertTrue(memcmp(bb_buffer, true_der, read_bytes) == 0, "digests did not match");
+
+ parcSigner_Release(&signer);
+ parcBuffer_Release(&pubkey_der);
+}
+
+LONGBOW_TEST_CASE(openssl_commandline, parcPkcs12KeyStore_VerifySignature_Cert)
+{
+ testUnimplemented("Not Implemented");
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_FileKeystore);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_PublicKeyECSigner.c b/libparc/parc/security/test/test_parc_PublicKeyECSigner.c
new file mode 100644
index 00000000..90ab1755
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_PublicKeyECSigner.c
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_PublicKeySigner.c"
+#include "../parc_InMemoryVerifier.c"
+#include <sys/param.h>
+
+#include <fcntl.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_PublicKeySigner.h>
+
+typedef struct test_data {
+ PARCSigner *signer;
+ PARCInMemoryVerifier *inMemoryInterface;
+} TestData;
+
+
+LONGBOW_TEST_RUNNER(parc_PublicKeySigner)
+{
+ // 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(parc_PublicKeySigner)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_PublicKeySigner)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ parcSecurity_Fini();
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *instance = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256);
+ parcKeyStore_Release(&keyStore);
+ assertNotNull(instance, "Expected non-null result from parcPublicKeySigner_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcPublicKeySigner_Acquire, instance);
+
+ parcPublicKeySigner_Release(&instance);
+ assertNull(instance, "Expected null result from parcPublicKeySigner_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcPublicKeySigner_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcPublicKeySigner_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcPublicKeySigner_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcPublicKeySigner_ToString);
+ LONGBOW_RUN_TEST_CASE(Object, parcPublicKeySigner_SignatureSize);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Object)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Object)
+{
+ parcSecurity_Fini();
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static PARCPublicKeySigner *
+_createSigner(char *path)
+{
+ char dirname[] = "/tmp/pubkeystore_XXXXXX";
+ char filename[MAXPATHLEN];
+
+ char *temporaryDirectory = mkdtemp(dirname);
+ assertNotNull(temporaryDirectory, "tmp_dirname should not be null");
+ sprintf(filename, "%s/%s", temporaryDirectory, path);
+
+ parcPkcs12KeyStore_CreateFile(filename, "blueberry", "person", PARCSigningAlgorithm_ECDSA, 256, 365);
+ PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open(filename, "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *publicKeyStore = parcKeyStore_Create(keyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&keyStore);
+ PARCPublicKeySigner *pksigner = parcPublicKeySigner_Create(publicKeyStore, PARCCryptoSuite_ECDSA_SHA256);
+ parcKeyStore_Release(&publicKeyStore);
+
+ return pksigner;
+}
+
+LONGBOW_TEST_CASE(Object, parcPublicKeySigner_Equals)
+{
+ PARCPublicKeySigner *x = _createSigner("bananasA");
+ PARCPublicKeySigner *y = _createSigner("bananasB");
+ PARCPublicKeySigner *z = _createSigner("bananasC");
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcPublicKeySigner_Release(&x);
+ parcPublicKeySigner_Release(&y);
+ parcPublicKeySigner_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Object, parcPublicKeySigner_HashCode)
+{
+ PARCPublicKeySigner *x = _createSigner("bananasX");
+ PARCPublicKeySigner *y = _createSigner("bananasY");
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcPublicKeySigner_Release(&x);
+ parcPublicKeySigner_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Object, parcPublicKeySigner_IsValid)
+{
+ PARCPublicKeySigner *instance = _createSigner("bananas");
+ assertTrue(parcPublicKeySigner_IsValid(instance), "Expected parcPublicKeySigner_Create to result in a valid instance.");
+
+ parcPublicKeySigner_Release(&instance);
+ assertFalse(parcPublicKeySigner_IsValid(instance), "Expected parcPublicKeySigner_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcPublicKeySigner_ToString)
+{
+ PARCPublicKeySigner *instance = _createSigner("bananas");
+
+ char *string = parcPublicKeySigner_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcPublicKeySigner_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcPublicKeySigner_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, parcPkcs12KeyStore_VerifySignature_Cert);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcPkcs12KeyStore_SignBuffer);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ parcSecurity_Init();
+
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256);
+ parcKeyStore_Release(&keyStore);
+
+ data->signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&ecSigner);
+ assertNotNull(data->signer, "Got null result from opening openssl pkcs12 file");
+
+ data->inMemoryInterface = parcInMemoryVerifier_Create();
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcInMemoryVerifier_Release(&data->inMemoryInterface);
+ parcSigner_Release(&data->signer);
+ parcMemory_Deallocate((void **) &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(Specialization, parcPkcs12KeyStore_VerifySignature_Cert)
+{
+}
+
+/**
+ * Sign the file "test_rsa_pub_sha256.bin" using the test_rsa.p12 private key.
+ */
+LONGBOW_TEST_CASE(Specialization, parcPkcs12KeyStore_SignBuffer)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256);
+ assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file");
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256);
+ parcKeyStore_Release(&keyStore);
+ PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&ecSigner);
+
+ PARCKey *key = parcSigner_CreatePublicKey(data->signer);
+ _parcInMemoryVerifier_AddKey(data->inMemoryInterface, key);
+
+ 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);
+
+ assertTrue(read_bytes > 0,
+ "Buffer to sign null: %zu",
+ read_bytes);
+
+ // Digest it
+ PARCCryptoHasher *digester = parcSigner_GetCryptoHasher(signer);
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes);
+ PARCCryptoHash *parcDigest = parcCryptoHasher_Finalize(digester);
+
+ assertTrue(parcBuffer_Remaining(parcCryptoHash_GetDigest(parcDigest)) >0,
+ "Incorrect signaturedigest size: %zu",
+ parcBuffer_Remaining(parcCryptoHash_GetDigest(parcDigest)));
+
+
+ PARCSignature *bb_test_sign = parcSigner_SignDigest(signer, parcDigest);
+
+ assertNotNull(bb_test_sign, "Got null byte buffer from SignBuffer");
+ assertTrue(parcBuffer_Remaining(parcSignature_GetSignature(bb_test_sign)) <= 72,
+ "Incorrect signature size: %zu",
+ parcBuffer_Remaining(parcSignature_GetSignature(bb_test_sign)));
+
+ bool success = _parcInMemoryVerifier_VerifyDigest(data->inMemoryInterface, parcKey_GetKeyId(key), parcDigest, PARCCryptoSuite_ECDSA_SHA256, bb_test_sign);
+
+ parcSigner_Release(&signer);
+ parcSignature_Release(&bb_test_sign);
+ parcCryptoHash_Release(&parcDigest);
+ parcKey_Release(&key);
+
+ assertTrue(success, "signatures did not match");
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_GetCertificateDigest)
+{
+ char dirname[] = "pubkeystore_XXXXXX";
+ char filename[MAXPATHLEN];
+ const char *password = "flumox";
+ unsigned key_bits = 256;
+ unsigned valid_days = 30;
+
+ const char to_sign[] = "it was a dark and stormy night, and all through the house not a digest was creeping";
+
+ char *tmp_dirname = mkdtemp(dirname);
+ assertNotNull(tmp_dirname, "tmp_dirname should not be null");
+ sprintf(filename, "%s/pubkeystore.p12", tmp_dirname);
+
+ // create the file
+ parcPkcs12KeyStore_CreateFile(filename, password, "alice", PARCSigningAlgorithm_ECDSA, key_bits, valid_days);
+
+ // open it as an RSA provider for the signer
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256);
+ PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&ecSigner);
+
+ PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBytes(hasher, to_sign, sizeof(to_sign));
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+ PARCSignature *sig = parcSigner_SignDigest(signer, hash);
+
+ unlink(filename);
+ int rc = rmdir(tmp_dirname);
+ assertTrue(rc == 0, "directory cleanup failed");
+
+ char *s = parcSignature_ToString(sig);
+ printf("Signature: %s\n", s);
+ parcMemory_Deallocate((void **) &s);
+
+ PARCCryptoHash *certDigest = parcKeyStore_GetCertificateDigest(parcSigner_GetKeyStore(signer));
+ assertNotNull(certDigest, "Expected a non NULL value");
+ parcCryptoHash_Release(&certDigest);
+
+ parcKeyStore_Release(&keyStore);
+ parcCryptoHash_Release(&hash);
+ parcSignature_Release(&sig);
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_GetDEREncodedCertificate)
+{
+ char dirname[] = "pubkeystore_XXXXXX";
+ char filename[MAXPATHLEN];
+ const char *password = "flumox";
+ unsigned key_bits = 256;
+ unsigned valid_days = 30;
+
+ const char to_sign[] = "it was a dark and stormy night, and all through the house not a digest was creeping";
+
+ char *tmp_dirname = mkdtemp(dirname);
+ assertNotNull(tmp_dirname, "tmp_dirname should not be null");
+ sprintf(filename, "%s/pubkeystore.p12", tmp_dirname);
+
+ // create the file
+ parcPkcs12KeyStore_CreateFile(filename, password, "alice", PARCSigningAlgorithm_ECDSA, key_bits, valid_days);
+
+ // open it as an RSA provider for the signer
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256);
+ PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&ecSigner);
+
+ PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBytes(hasher, to_sign, sizeof(to_sign));
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+ PARCSignature *sig = parcSigner_SignDigest(signer, hash);
+
+ unlink(filename);
+ int rc = rmdir(tmp_dirname);
+ assertTrue(rc == 0, "directory cleanup failed");
+
+ char *s = parcSignature_ToString(sig);
+ printf("Signature: %s\n", s);
+ parcMemory_Deallocate((void **) &s);
+
+ PARCBuffer *certificate_der = parcKeyStore_GetDEREncodedCertificate(parcSigner_GetKeyStore(signer));
+ assertNotNull(certificate_der, "Expected a non NULL value");
+ parcBuffer_Release(&certificate_der);
+
+ parcKeyStore_Release(&keyStore);
+ parcCryptoHash_Release(&hash);
+ parcSignature_Release(&sig);
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_CreatePublicKey)
+{
+ char dirname[] = "pubkeystore_XXXXXX";
+ char filename[MAXPATHLEN];
+ const char *password = "flumox";
+ unsigned key_bits = 256;
+ unsigned valid_days = 30;
+
+ char *tmp_dirname = mkdtemp(dirname);
+ assertNotNull(tmp_dirname, "tmp_dirname should not be null");
+ sprintf(filename, "%s/pubkeystore.p12", tmp_dirname);
+
+ // create the file
+ parcPkcs12KeyStore_CreateFile(filename, password, "alice", PARCSigningAlgorithm_ECDSA, key_bits, valid_days);
+
+ // open it as an RSA provider for the signer
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256);
+ PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&ecSigner);
+
+ PARCKey *key = parcSigner_CreatePublicKey(signer);
+ assertNotNull(key, "Expected a non NULL value");
+ parcKey_Release(&key);
+ parcKeyStore_Release(&keyStore);
+
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_CreateKeyId)
+{
+ char dirname[] = "pubkeystore_XXXXXX";
+ char filename[MAXPATHLEN];
+ const char *password = "flumox";
+ unsigned key_bits = 256;
+ unsigned valid_days = 30;
+
+ const char to_sign[] = "it was a dark and stormy night, and all through the house not a digest was creeping";
+
+ char *tmp_dirname = mkdtemp(dirname);
+ assertNotNull(tmp_dirname, "tmp_dirname should not be null");
+ sprintf(filename, "%s/pubkeystore.p12", tmp_dirname);
+
+ // create the file
+ parcPkcs12KeyStore_CreateFile(filename, password, "alice", PARCSigningAlgorithm_ECDSA, key_bits, valid_days);
+
+ // open it as an RSA provider for the signer
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *ecSigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_ECDSA_SHA256);
+ PARCSigner *signer = parcSigner_Create(ecSigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&ecSigner);
+
+ PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBytes(hasher, to_sign, sizeof(to_sign));
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+ PARCSignature *sig = parcSigner_SignDigest(signer, hash);
+
+ unlink(filename);
+ int rc = rmdir(tmp_dirname);
+ assertTrue(rc == 0, "directory cleanup failed");
+
+ char *s = parcSignature_ToString(sig);
+ printf("Signature: %s\n", s);
+ parcMemory_Deallocate((void **) &s);
+
+ PARCKeyId *keyId = parcSigner_CreateKeyId(signer);
+ assertNotNull(keyId, "Expected a non NULL value");
+ parcKeyId_Release(&keyId);
+
+ parcKeyStore_Release(&keyStore);
+ parcCryptoHash_Release(&hash);
+ parcSignature_Release(&sig);
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Object, parcPublicKeySigner_SignatureSize)
+{
+ PARCPublicKeySigner *publicKeySigner = _createSigner("test_key_size");
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+
+ assertTrue(parcSigner_GetSignatureSize(signer) == 72, "Key size unexpected %lu ", parcSigner_GetSignatureSize(signer));
+ parcPublicKeySigner_Release(&publicKeySigner);
+ parcSigner_Release(&signer);
+}
+
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_PublicKeySigner);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_PublicKeySigner.c b/libparc/parc/security/test/test_parc_PublicKeySigner.c
new file mode 100644
index 00000000..69fb7049
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_PublicKeySigner.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 "../parc_PublicKeySigner.c"
+#include <sys/param.h>
+
+#include <fcntl.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+
+LONGBOW_TEST_RUNNER(parc_PublicKeySigner)
+{
+ // 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(parc_PublicKeySigner)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_PublicKeySigner)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ parcSecurity_Fini();
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *instance = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256);
+ parcKeyStore_Release(&keyStore);
+ assertNotNull(instance, "Expected non-null result from parcPublicKeySigner_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcPublicKeySigner_Acquire, instance);
+
+ parcPublicKeySigner_Release(&instance);
+ assertNull(instance, "Expected null result from parcPublicKeySigner_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcPublicKeySigner_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcPublicKeySigner_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcPublicKeySigner_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcPublicKeySigner_ToString);
+ LONGBOW_RUN_TEST_CASE(Object, parcPublicKeySigner_SignatureSize);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Object)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Object)
+{
+ parcSecurity_Fini();
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static PARCPublicKeySigner *
+_createSigner(char *path)
+{
+ char dirname[] = "/tmp/pubkeystore_XXXXXX";
+ char filename[MAXPATHLEN];
+
+ char *temporaryDirectory = mkdtemp(dirname);
+ assertNotNull(temporaryDirectory, "tmp_dirname should not be null");
+ sprintf(filename, "%s/%s", temporaryDirectory, path);
+
+ parcPkcs12KeyStore_CreateFile(filename, "blueberry", "person", PARCSigningAlgorithm_RSA, 1024, 365);
+ PARCPkcs12KeyStore *keyStore = parcPkcs12KeyStore_Open(filename, "blueberry", PARCCryptoHashType_SHA256);
+ PARCKeyStore *publicKeyStore = parcKeyStore_Create(keyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&keyStore);
+ PARCPublicKeySigner *pksigner = parcPublicKeySigner_Create(publicKeyStore, PARCCryptoSuite_RSA_SHA256);
+ parcKeyStore_Release(&publicKeyStore);
+
+ return pksigner;
+}
+
+LONGBOW_TEST_CASE(Object, parcPublicKeySigner_Equals)
+{
+ PARCPublicKeySigner *x = _createSigner("bananasA");
+ PARCPublicKeySigner *y = _createSigner("bananasB");
+ PARCPublicKeySigner *z = _createSigner("bananasC");
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcPublicKeySigner_Release(&x);
+ parcPublicKeySigner_Release(&y);
+ parcPublicKeySigner_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Object, parcPublicKeySigner_HashCode)
+{
+ PARCPublicKeySigner *x = _createSigner("bananasX");
+ PARCPublicKeySigner *y = _createSigner("bananasY");
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcPublicKeySigner_Release(&x);
+ parcPublicKeySigner_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Object, parcPublicKeySigner_IsValid)
+{
+ PARCPublicKeySigner *instance = _createSigner("bananas");
+ assertTrue(parcPublicKeySigner_IsValid(instance), "Expected parcPublicKeySigner_Create to result in a valid instance.");
+
+ parcPublicKeySigner_Release(&instance);
+ assertFalse(parcPublicKeySigner_IsValid(instance), "Expected parcPublicKeySigner_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcPublicKeySigner_ToString)
+{
+ PARCPublicKeySigner *instance = _createSigner("bananas");
+
+ char *string = parcPublicKeySigner_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcPublicKeySigner_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcPublicKeySigner_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, parcPkcs12KeyStore_VerifySignature_Cert);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcPkcs12KeyStore_SignBuffer);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ parcSecurity_Fini();
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Specialization, parcPkcs12KeyStore_VerifySignature_Cert)
+{
+}
+
+/**
+ * Sign the file "test_rsa_pub_sha256.bin" using the test_rsa.p12 private key.
+ */
+LONGBOW_TEST_CASE(Specialization, parcPkcs12KeyStore_SignBuffer)
+{
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+ assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file");
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256);
+ parcKeyStore_Release(&keyStore);
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+
+ 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);
+
+ // Digest it
+ PARCCryptoHasher *digester = parcSigner_GetCryptoHasher(signer);
+ parcCryptoHasher_Init(digester);
+ parcCryptoHasher_UpdateBytes(digester, buffer_to_sign, read_bytes);
+ PARCCryptoHash *parcDigest = parcCryptoHasher_Finalize(digester);
+
+ PARCSignature *bb_test_sign = parcSigner_SignDigest(signer, parcDigest);
+
+ assertNotNull(bb_test_sign, "Got null byte buffer from SignBuffer");
+ assertTrue(parcBuffer_Remaining(parcSignature_GetSignature(bb_test_sign)) == 128,
+ "Incorrect signature size: %zu",
+ parcBuffer_Position(parcSignature_GetSignature(bb_test_sign)));
+
+ // 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);
+
+ const unsigned char *actual = parcByteArray_Array(parcBuffer_Array(parcSignature_GetSignature(bb_test_sign)));
+
+ assertTrue(memcmp(scratch_buffer, actual, read_bytes) == 0,
+ "signatures did not match");
+
+ parcSigner_Release(&signer);
+ parcSignature_Release(&bb_test_sign);
+ parcCryptoHash_Release(&parcDigest);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_GetCertificateDigest)
+{
+ char dirname[] = "pubkeystore_XXXXXX";
+ char filename[MAXPATHLEN];
+ const char *password = "flumox";
+ unsigned key_bits = 1024;
+ unsigned valid_days = 30;
+
+ const char to_sign[] = "it was a dark and stormy night, and all through the house not a digest was creeping";
+
+ char *tmp_dirname = mkdtemp(dirname);
+ assertNotNull(tmp_dirname, "tmp_dirname should not be null");
+ sprintf(filename, "%s/pubkeystore.p12", tmp_dirname);
+
+ // create the file
+ parcPkcs12KeyStore_CreateFile(filename, password, "alice", PARCSigningAlgorithm_RSA, key_bits, valid_days);
+
+ // open it as an RSA provider for the signer
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256);
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+
+ PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBytes(hasher, to_sign, sizeof(to_sign));
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+ PARCSignature *sig = parcSigner_SignDigest(signer, hash);
+
+ unlink(filename);
+ int rc = rmdir(tmp_dirname);
+ assertTrue(rc == 0, "directory cleanup failed");
+
+ char *s = parcSignature_ToString(sig);
+ printf("Signature: %s\n", s);
+ parcMemory_Deallocate((void **) &s);
+
+ PARCCryptoHash *certDigest = parcKeyStore_GetCertificateDigest(parcSigner_GetKeyStore(signer));
+ assertNotNull(certDigest, "Expected a non NULL value");
+ parcCryptoHash_Release(&certDigest);
+
+ parcKeyStore_Release(&keyStore);
+ parcCryptoHash_Release(&hash);
+ parcSignature_Release(&sig);
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_GetDEREncodedCertificate)
+{
+ char dirname[] = "pubkeystore_XXXXXX";
+ char filename[MAXPATHLEN];
+ const char *password = "flumox";
+ unsigned key_bits = 1024;
+ unsigned valid_days = 30;
+
+ const char to_sign[] = "it was a dark and stormy night, and all through the house not a digest was creeping";
+
+ char *tmp_dirname = mkdtemp(dirname);
+ assertNotNull(tmp_dirname, "tmp_dirname should not be null");
+ sprintf(filename, "%s/pubkeystore.p12", tmp_dirname);
+
+ // create the file
+ parcPkcs12KeyStore_CreateFile(filename, password, "alice", PARCSigningAlgorithm_RSA, key_bits, valid_days);
+
+ // open it as an RSA provider for the signer
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256);
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+
+ PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBytes(hasher, to_sign, sizeof(to_sign));
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+ PARCSignature *sig = parcSigner_SignDigest(signer, hash);
+
+ unlink(filename);
+ int rc = rmdir(tmp_dirname);
+ assertTrue(rc == 0, "directory cleanup failed");
+
+ char *s = parcSignature_ToString(sig);
+ printf("Signature: %s\n", s);
+ parcMemory_Deallocate((void **) &s);
+
+ PARCBuffer *certificate_der = parcKeyStore_GetDEREncodedCertificate(parcSigner_GetKeyStore(signer));
+ assertNotNull(certificate_der, "Expected a non NULL value");
+ parcBuffer_Release(&certificate_der);
+
+ parcKeyStore_Release(&keyStore);
+ parcCryptoHash_Release(&hash);
+ parcSignature_Release(&sig);
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_CreatePublicKey)
+{
+ char dirname[] = "pubkeystore_XXXXXX";
+ char filename[MAXPATHLEN];
+ const char *password = "flumox";
+ unsigned key_bits = 1024;
+ unsigned valid_days = 30;
+
+ char *tmp_dirname = mkdtemp(dirname);
+ assertNotNull(tmp_dirname, "tmp_dirname should not be null");
+ sprintf(filename, "%s/pubkeystore.p12", tmp_dirname);
+
+ // create the file
+ parcPkcs12KeyStore_CreateFile(filename, password, "alice", PARCSigningAlgorithm_RSA, key_bits, valid_days);
+
+ // open it as an RSA provider for the signer
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256);
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+
+ PARCKey *key = parcSigner_CreatePublicKey(signer);
+ assertNotNull(key, "Expected a non NULL value");
+ parcKey_Release(&key);
+ parcKeyStore_Release(&keyStore);
+
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_CreateKeyId)
+{
+ char dirname[] = "pubkeystore_XXXXXX";
+ char filename[MAXPATHLEN];
+ const char *password = "flumox";
+ unsigned key_bits = 1024;
+ unsigned valid_days = 30;
+
+ const char to_sign[] = "it was a dark and stormy night, and all through the house not a digest was creeping";
+
+ char *tmp_dirname = mkdtemp(dirname);
+ assertNotNull(tmp_dirname, "tmp_dirname should not be null");
+ sprintf(filename, "%s/pubkeystore.p12", tmp_dirname);
+
+ // create the file
+ parcPkcs12KeyStore_CreateFile(filename, password, "alice", PARCSigningAlgorithm_RSA, key_bits, valid_days);
+
+ // open it as an RSA provider for the signer
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open(filename, password, PARCCryptoHashType_SHA256);
+ PARCKeyStore *keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ PARCPublicKeySigner *publicKeySigner = parcPublicKeySigner_Create(keyStore, PARCCryptoSuite_RSA_SHA256);
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+ parcPublicKeySigner_Release(&publicKeySigner);
+
+ PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBytes(hasher, to_sign, sizeof(to_sign));
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+ PARCSignature *sig = parcSigner_SignDigest(signer, hash);
+
+ unlink(filename);
+ int rc = rmdir(tmp_dirname);
+ assertTrue(rc == 0, "directory cleanup failed");
+
+ char *s = parcSignature_ToString(sig);
+ printf("Signature: %s\n", s);
+ parcMemory_Deallocate((void **) &s);
+
+ PARCKeyId *keyId = parcSigner_CreateKeyId(signer);
+ assertNotNull(keyId, "Expected a non NULL value");
+ parcKeyId_Release(&keyId);
+
+ parcKeyStore_Release(&keyStore);
+ parcCryptoHash_Release(&hash);
+ parcSignature_Release(&sig);
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Object, parcPublicKeySigner_SignatureSize)
+{
+ PARCPublicKeySigner *publicKeySigner = _createSigner("test_key_size");
+ PARCSigner *signer = parcSigner_Create(publicKeySigner, PARCPublicKeySignerAsSigner);
+
+
+ assertTrue(parcSigner_GetSignatureSize(signer) == 128, "Modulus size unexpected %lu ", parcSigner_GetSignatureSize(signer));
+ parcPublicKeySigner_Release(&publicKeySigner);
+ parcSigner_Release(&signer);
+}
+
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_PublicKeySigner);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_SecureRandom.c b/libparc/parc/security/test/test_parc_SecureRandom.c
new file mode 100755
index 00000000..82359a70
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_SecureRandom.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 "../parc_SecureRandom.c"
+#include <sys/param.h>
+
+#include <fcntl.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <parc/security/parc_Security.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_LinkedList.h>
+
+#include <parc/testing/parc_MemoryTesting.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#define NUM_TESTS 1000
+#define EPSILON 0.01
+
+LONGBOW_TEST_RUNNER(parc_SecureRandom)
+{
+ // 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(parc_SecureRandom)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_SecureRandom)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateAcquireRelease)
+{
+ parcSecurity_Fini();
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s leaked memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateAcquireRelease, CreateRelease)
+{
+ PARCSecureRandom *rng = parcSecureRandom_Create();
+ assertNotNull(rng, "Expected non-null result from parcSecureRandom_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcSecureRandom_Acquire, rng);
+
+ parcSecureRandom_Release(&rng);
+ assertNull(rng, "Expected null result from parcSecureRandom_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcSecureRandom_IsValid);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Object)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Object)
+{
+ parcSecurity_Fini();
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Object, parcSecureRandom_IsValid)
+{
+ PARCSecureRandom *rng = parcSecureRandom_Create();
+ assertNotNull(rng, "Expected a non-NULL PARCSecureRandom");
+
+ assertTrue(parcSecureRandom_IsValid(rng), "Expected parcSecureRandom_Create to result in a valid instance.");
+
+ parcSecureRandom_Release(&rng);
+ assertFalse(parcSecureRandom_IsValid(rng), "Expected parcSecureRandom_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSecureRandom_Create);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSecureRandom_CreateWithSeed);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSecureRandom_Next);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcSecureRandom_NextBytes);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ parcSecurity_Fini();
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSecureRandom_Create)
+{
+ PARCSecureRandom *rng = parcSecureRandom_Create();
+ assertTrue(parcSecureRandom_IsValid(rng), "Expected parcSecureRandom_Create to result in a valid instance.");
+ parcSecureRandom_Release(&rng);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSecureRandom_CreateWithSeed)
+{
+ PARCBuffer *seed = parcBuffer_Allocate(1024);
+ PARCSecureRandom *rng = parcSecureRandom_CreateWithSeed(seed);
+
+ assertTrue(parcSecureRandom_IsValid(rng), "Expected parcSecureRandom_CreateWithSeed to result in a valid instance.");
+
+ parcSecureRandom_Release(&rng);
+ parcBuffer_Release(&seed);
+}
+
+static void
+_stressTestNext(PARCSecureRandom *rng)
+{
+ PARCLinkedList *seen = parcLinkedList_Create();
+ size_t duplicates = 0;
+ for (size_t i = 0; i < NUM_TESTS; i++) {
+ uint32_t next = parcSecureRandom_Next(rng);
+ PARCBuffer *buffer = parcBuffer_Allocate(sizeof(next));
+ parcBuffer_Flip(parcBuffer_PutUint32(buffer, next));
+
+ if (parcLinkedList_Contains(seen, buffer)) {
+ duplicates++;
+ } else {
+ parcLinkedList_Append(seen, buffer);
+ }
+
+ parcBuffer_Release(&buffer);
+ }
+
+ assertFalse(duplicates > (NUM_TESTS * EPSILON), "The RNG failed to generate random values: saw %zu duplicates", duplicates);
+ parcLinkedList_Release(&seen);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSecureRandom_Next)
+{
+ PARCSecureRandom *rng = parcSecureRandom_Create();
+ assertTrue(parcSecureRandom_IsValid(rng), "Expected parcSecureRandom_Create to result in a valid instance");
+ _stressTestNext(rng);
+ parcSecureRandom_Release(&rng);
+}
+
+static void
+_stressTestNextBytes(PARCSecureRandom *rng)
+{
+ PARCLinkedList *seen = parcLinkedList_Create();
+ size_t duplicates = 0;
+ for (size_t i = 0; i < NUM_TESTS; i++) {
+ PARCBuffer *buffer = parcBuffer_Allocate(32);
+
+ int numBytes = parcSecureRandom_NextBytes(rng, buffer);
+ assertTrue(numBytes == 32, "Expected 32 bytes from the RNG, got %d", numBytes);
+
+ if (parcLinkedList_Contains(seen, buffer)) {
+ duplicates++;
+ } else {
+ parcLinkedList_Append(seen, buffer);
+ }
+
+ parcBuffer_Release(&buffer);
+ }
+
+ assertFalse(duplicates > (NUM_TESTS * EPSILON), "The RNG failed to generate random values: saw %zu duplicates", duplicates);
+ parcLinkedList_Release(&seen);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcSecureRandom_NextBytes)
+{
+ PARCBuffer *seed = parcBuffer_Allocate(1024);
+ PARCSecureRandom *rng = parcSecureRandom_CreateWithSeed(seed);
+
+ assertTrue(parcSecureRandom_IsValid(rng), "Expected parcSecureRandom_CreateWithSeed to result in a valid instance.");
+ _stressTestNextBytes(rng);
+
+ parcSecureRandom_Release(&rng);
+ parcBuffer_Release(&seed);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_SecureRandom);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_Security.c b/libparc/parc/security/test/test_parc_Security.c
new file mode 100755
index 00000000..c2f2f33e
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_Security.c
@@ -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.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Security.c"
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(parc_Security)
+{
+ // 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(parc_Security)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Security)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcSecurity_Fini);
+ LONGBOW_RUN_TEST_CASE(Global, parcSecurity_Init);
+ LONGBOW_RUN_TEST_CASE(Global, parcSecurity_Init_Multiple);
+ LONGBOW_RUN_TEST_CASE(Global, parcSecurity_IsInitialized);
+}
+
+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, parcSecurity_Fini)
+{
+ parcSecurity_Init();
+ parcSecurity_AssertIsInitialized();
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_CASE(Global, parcSecurity_Init)
+{
+ parcSecurity_Init();
+ parcSecurity_AssertIsInitialized();
+ parcSecurity_Fini();
+}
+
+LONGBOW_TEST_CASE(Global, parcSecurity_Init_Multiple)
+{
+ parcSecurity_Init();
+ parcSecurity_Init();
+ parcSecurity_Init();
+ parcSecurity_Init();
+ parcSecurity_AssertIsInitialized();
+ parcSecurity_Fini();
+ parcSecurity_Fini();
+ parcSecurity_Fini();
+ parcSecurity_Fini();
+ assertFalse(parcSecurity_IsInitialized(), "parcSecurity_IsInitialized should be false now");
+}
+
+LONGBOW_TEST_CASE(Global, parcSecurity_IsInitialized)
+{
+ parcSecurity_Init();
+ parcSecurity_AssertIsInitialized();
+ parcSecurity_Fini();
+ assertFalse(parcSecurity_IsInitialized(), "parcSecurity_IsInitialized should be false now");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Security);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_Signature.c b/libparc/parc/security/test/test_parc_Signature.c
new file mode 100755
index 00000000..4c57d5a9
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_Signature.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_Signature.c"
+#include <inttypes.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_Signature)
+{
+ // 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(parc_Signature)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Signature)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcSignature_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcSignature_Acquire);
+ LONGBOW_RUN_TEST_CASE(Global, parcSignature_Release);
+ LONGBOW_RUN_TEST_CASE(Global, parcSignature_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcSignature_GetHashType);
+ LONGBOW_RUN_TEST_CASE(Global, parcSignature_GetSignature);
+ LONGBOW_RUN_TEST_CASE(Global, parcSignature_GetSigningAlgorithm);
+ LONGBOW_RUN_TEST_CASE(Global, parcSignature_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, parcSignature_Create)
+{
+ PARCBuffer *bits = parcBuffer_Allocate(10); // arbitrary buffer size -- not important
+ PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, bits);
+ parcBuffer_Release(&bits);
+
+ assertNotNull(signature, "Expected non-NULL PARCSignature");
+ PARCReferenceCount referenceCount = parcObject_GetReferenceCount(signature);
+ assertTrue(referenceCount == 1,
+ "Expected reference count to be equal to 1, got %" PRIu64 "",
+ referenceCount);
+
+ parcSignature_Release(&signature);
+}
+
+LONGBOW_TEST_CASE(Global, parcSignature_Acquire)
+{
+ PARCBuffer *bits = parcBuffer_Allocate(10); // arbitrary buffer size -- not important
+ PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, bits);
+ PARCSignature *handle = parcSignature_Acquire(signature);
+ parcBuffer_Release(&bits);
+
+ assertNotNull(signature, "Expected non-NULL PARCSignature");
+ assertNotNull(handle, "Expected non-NULL PARCSignature after acquisition");
+ PARCReferenceCount referenceCount = parcObject_GetReferenceCount(handle);
+ assertTrue(referenceCount == 2,
+ "Expected reference count to be equal to 2, got %" PRIu64 "",
+ referenceCount);
+
+ parcSignature_Release(&signature);
+ parcSignature_Release(&handle);
+}
+
+LONGBOW_TEST_CASE(Global, parcSignature_Release)
+{
+ PARCBuffer *bits = parcBuffer_Allocate(10); // arbitrary bufer size -- not important
+ PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, bits);
+ PARCSignature *handle = parcSignature_Acquire(signature);
+ parcBuffer_Release(&bits);
+
+ assertNotNull(signature, "Expected non-NULL PARCSignature");
+ assertNotNull(handle, "Expected non-NULL PARCSignature after acquisition");
+ PARCReferenceCount referenceCount = parcObject_GetReferenceCount(handle);
+ assertTrue(referenceCount == 2,
+ "Expected reference count to be equal to 2, got %" PRIu64 "",
+ referenceCount);
+
+ parcSignature_Release(&signature);
+ parcSignature_Release(&handle);
+
+ assertNull(signature, "Expected NULL PARCSignature");
+}
+
+LONGBOW_TEST_CASE(Global, parcSignature_Equals)
+{
+ PARCBuffer *bits = parcBuffer_Allocate(10); // arbitrary bufer size -- not important
+ PARCBuffer *otherBits = parcBuffer_Allocate(strlen("hello"));
+ parcBuffer_PutArray(otherBits, strlen("hello"), (uint8_t *) "hello");
+
+ PARCSignature *x = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, bits);
+ PARCSignature *y = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, bits);
+ PARCSignature *z = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, bits);
+ PARCSignature *unequal1 = parcSignature_Create(PARCSigningAlgorithm_HMAC, PARCCryptoHashType_SHA256, bits);
+ PARCSignature *unequal2 = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_CRC32C, bits);
+ PARCSignature *unequal3 = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, otherBits);
+
+ parcObjectTesting_AssertEqualsFunction(parcSignature_Equals, x, y, z, unequal1, unequal2, unequal3, NULL);
+
+ parcSignature_Release(&x);
+ parcSignature_Release(&y);
+ parcSignature_Release(&z);
+ parcSignature_Release(&unequal1);
+ parcSignature_Release(&unequal2);
+ parcSignature_Release(&unequal3);
+
+ parcBuffer_Release(&bits);
+ parcBuffer_Release(&otherBits);
+}
+
+LONGBOW_TEST_CASE(Global, parcSignature_GetHashType)
+{
+ PARCBuffer *bits = parcBuffer_Allocate(strlen("Hello"));
+ parcBuffer_PutArray(bits, strlen("Hello"), (uint8_t *) "Hello");
+ PARCCryptoHashType expected = PARCCryptoHashType_SHA256;
+ PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_ECDSA, expected, bits);
+ parcBuffer_Release(&bits);
+
+ PARCCryptoHashType actual = parcSignature_GetHashType(signature);
+
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+ parcSignature_Release(&signature);
+}
+
+LONGBOW_TEST_CASE(Global, parcSignature_GetSignature)
+{
+ PARCBuffer *expected = parcBuffer_Allocate(strlen("Hello"));
+ parcBuffer_PutArray(expected, strlen("Hello"), (uint8_t *) "Hello");
+ PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, expected);
+
+ PARCBuffer *actual = parcSignature_GetSignature(signature);
+
+ assertTrue(parcBuffer_Equals(expected, actual), "Expected the original signature bits to be equal to the actual bits");
+ parcSignature_Release(&signature);
+ parcBuffer_Release(&expected);
+}
+
+LONGBOW_TEST_CASE(Global, parcSignature_GetSigningAlgorithm)
+{
+ PARCBuffer *signatureBits = parcBuffer_Allocate(strlen("Hello"));
+ parcBuffer_PutArray(signatureBits, strlen("Hello"), (uint8_t *) "Hello");
+ PARCSigningAlgorithm expected = PARCSigningAlgorithm_ECDSA;
+ PARCSignature *signature = parcSignature_Create(expected, PARCCryptoHashType_SHA256, signatureBits);
+
+ PARCSigningAlgorithm actual = parcSignature_GetSigningAlgorithm(signature);
+
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+ parcSignature_Release(&signature);
+ parcBuffer_Release(&signatureBits);
+}
+
+LONGBOW_TEST_CASE(Global, parcSignature_ToString)
+{
+ PARCBuffer *signatureBits = parcBuffer_Allocate(strlen("Hello"));
+ parcBuffer_PutArray(signatureBits, strlen("Hello"), (uint8_t *) "Hello");
+ PARCSigningAlgorithm expected = PARCSigningAlgorithm_ECDSA;
+ PARCSignature *signature = parcSignature_Create(expected, PARCCryptoHashType_SHA256, signatureBits);
+
+ char *string = parcSignature_ToString(signature);
+
+ assertNotNull(string, "Expected non-NULL result from parcSignature_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcSignature_Release(&signature);
+ parcBuffer_Release(&signatureBits);
+}
+
+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(parc_Signature);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_Signer.c b/libparc/parc/security/test/test_parc_Signer.c
new file mode 100644
index 00000000..b9605384
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_Signer.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/unit-test.h>
+#include <sys/param.h>
+#include <errno.h>
+
+#include "../parc_Signer.c"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_Security.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_KeyStore.h>
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_SymmetricKeySigner.h>
+
+#define FAKE_SIGNATURE "signature"
+
+typedef struct {
+ PARCCryptoHasher *hasher;
+ PARCKeyStore *keyStore;
+} _MockSigner;
+
+static PARCSignature *
+_SignDigest(PARCSigner *interfaceContext)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString(FAKE_SIGNATURE);
+ PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_RSA, PARCCryptoHashType_SHA256, buffer);
+ parcBuffer_Release(&buffer);
+ return signature;
+}
+
+static PARCSigningAlgorithm
+_GetSigningAlgorithm(PARCSigner *interfaceContext)
+{
+ return PARCSigningAlgorithm_RSA;
+}
+
+static PARCCryptoHashType
+_GetCryptoHashType(PARCSigner *signer)
+{
+ return PARCCryptoHashType_SHA256;
+}
+
+static PARCCryptoHasher *
+_GetCryptoHasher(_MockSigner *signer)
+{
+ return signer->hasher;
+}
+
+static PARCKeyStore *
+_GetKeyStore(_MockSigner *signer)
+{
+ return signer->keyStore;
+}
+
+static bool
+_releaseSigner(_MockSigner **signer)
+{
+ parcCryptoHasher_Release(&((*signer)->hasher));
+ parcKeyStore_Release(&((*signer)->keyStore));
+ return true;
+}
+
+parcObject_ImplementAcquire(_mockSigner, _MockSigner);
+parcObject_ImplementRelease(_mockSigner, _MockSigner);
+
+parcObject_Override(_MockSigner, PARCObject,
+ .destructor = (PARCObjectDestructor *) _releaseSigner);
+
+static _MockSigner *
+_createSigner()
+{
+ _MockSigner *signer = parcObject_CreateInstance(_MockSigner);
+
+ signer->hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_rsa.p12", "blueberry", PARCCryptoHashType_SHA256);
+ assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file");
+
+ signer->keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ return signer;
+}
+
+static PARCSigningInterface *_MockSignerInterface = &(PARCSigningInterface) {
+ .GetCryptoHasher = (PARCCryptoHasher * (*)(void *))_GetCryptoHasher,
+ .SignDigest = (PARCSignature * (*)(void *, const PARCCryptoHash *))_SignDigest,
+ .GetSigningAlgorithm = (PARCSigningAlgorithm (*)(void *))_GetSigningAlgorithm,
+ .GetCryptoHashType = (PARCCryptoHashType (*)(void *))_GetCryptoHashType,
+ .GetKeyStore = (PARCKeyStore * (*)(void *))_GetKeyStore,
+};
+
+LONGBOW_TEST_RUNNER(parc_Signer)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Signer)
+{
+ 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_Signer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_CreateKeyId);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_CreatePublicKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_GetCryptoHasher);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_SignDigest);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_GetSigningAlgorithm);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_GetCryptoHashType);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_GetKeyStore);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ 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(Global, parcSigner_Create)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+ _mockSigner_Release(&mock);
+
+ assertNotNull(signer, "Expected non-null signer");
+
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_AcquireRelease)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+ _mockSigner_Release(&mock);
+
+ assertNotNull(signer, "Expected non-null signer");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcSigner_Acquire, signer);
+
+ parcSigner_Release(&signer);
+ assertNull(signer, "Expected null result from parcSigner_Release();");
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_CreateKeyId)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+ _mockSigner_Release(&mock);
+
+ PARCKeyId *keyId = parcSigner_CreateKeyId(signer);
+
+ assertNotNull(keyId, "Expected non-NULL PARCKeyId");
+
+ parcKeyId_Release(&keyId);
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_CreatePublicKey)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+
+ PARCKey *key = parcSigner_CreatePublicKey(signer);
+
+ // Compute the real value
+ PARCCryptoHash *hash = parcKeyStore_GetVerifierKeyDigest(mock->keyStore);
+ PARCKeyId *keyid = parcKeyId_Create(parcCryptoHash_GetDigest(hash));
+ PARCBuffer *derEncodedKey = parcKeyStore_GetDEREncodedPublicKey(mock->keyStore);
+
+ PARCKey *expectedKey = parcKey_CreateFromDerEncodedPublicKey(keyid,
+ parcSigner_GetSigningAlgorithm(signer),
+ derEncodedKey);
+
+ parcBuffer_Release(&derEncodedKey);
+ parcKeyId_Release(&keyid);
+
+ parcCryptoHash_Release(&hash);
+
+ assertTrue(parcKey_Equals(key, expectedKey), "Expected public keys to be computed equally.");
+
+ parcKey_Release(&key);
+ parcKey_Release(&expectedKey);
+ parcSigner_Release(&signer);
+ _mockSigner_Release(&mock);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_GetCryptoHasher)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+ _mockSigner_Release(&mock);
+
+ PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer);
+
+ assertNotNull(hasher, "Expected non-NULL PARCCryptoHasher");
+
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_SignDigest)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+ _mockSigner_Release(&mock);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+ PARCSignature *signature = parcSigner_SignDigest(signer, hash);
+
+ assertNotNull(signature, "Expected non-NULL PARCSignature");
+
+ PARCBuffer *bits = parcSignature_GetSignature(signature);
+ char *bitstring = parcBuffer_ToString(bits);
+ char *expectedString = FAKE_SIGNATURE;
+ assertTrue(strcmp(bitstring, expectedString) == 0, "Expected the forced signature as output %s, got %s", expectedString, bitstring);
+ parcMemory_Deallocate(&bitstring);
+
+ parcCryptoHash_Release(&hash);
+ parcBuffer_Release(&buffer);
+ parcSignature_Release(&signature);
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_GetSigningAlgorithm)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+ _mockSigner_Release(&mock);
+
+ PARCSigningAlgorithm alg = parcSigner_GetSigningAlgorithm(signer);
+ assertTrue(PARCSigningAlgorithm_RSA == alg, "Expected PARCSigningAlgorithm_RSA algorithm, got %d", alg);
+
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_GetCryptoHashType)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+ _mockSigner_Release(&mock);
+
+ PARCCryptoHashType type = parcSigner_GetCryptoHashType(signer);
+ assertTrue(PARCCryptoHashType_SHA256 == type, "Expected PARCCryptoHashType_SHA256 algorithm, got %d", type);
+
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_GetKeyStore)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+ _mockSigner_Release(&mock);
+
+ PARCKeyStore *keyStore = parcSigner_GetKeyStore(signer);
+ assertNotNull(keyStore, "Expected non-NULL PARCKeyStore");
+
+ parcSigner_Release(&signer);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Signer);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_SignerEC.c b/libparc/parc/security/test/test_parc_SignerEC.c
new file mode 100644
index 00000000..2b6fc577
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_SignerEC.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/unit-test.h>
+#include <sys/param.h>
+#include <errno.h>
+
+#include "../parc_Signer.c"
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_Security.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_KeyStore.h>
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_SymmetricKeySigner.h>
+
+#define FAKE_SIGNATURE "signature"
+
+typedef struct {
+ PARCCryptoHasher *hasher;
+ PARCKeyStore *keyStore;
+} _MockSigner;
+
+static PARCSignature *
+_SignDigest(PARCSigner *interfaceContext)
+{
+ PARCBuffer *buffer = parcBuffer_WrapCString(FAKE_SIGNATURE);
+ PARCSignature *signature = parcSignature_Create(PARCSigningAlgorithm_ECDSA, PARCCryptoHashType_SHA256, buffer);
+ parcBuffer_Release(&buffer);
+ return signature;
+}
+
+static PARCSigningAlgorithm
+_GetSigningAlgorithm(PARCSigner *interfaceContext)
+{
+ return PARCSigningAlgorithm_ECDSA;
+}
+
+static PARCCryptoHashType
+_GetCryptoHashType(PARCSigner *signer)
+{
+ return PARCCryptoHashType_SHA256;
+}
+
+static PARCCryptoHasher *
+_GetCryptoHasher(_MockSigner *signer)
+{
+ return signer->hasher;
+}
+
+static PARCKeyStore *
+_GetKeyStore(_MockSigner *signer)
+{
+ return signer->keyStore;
+}
+
+static bool
+_releaseSigner(_MockSigner **signer)
+{
+ parcCryptoHasher_Release(&((*signer)->hasher));
+ parcKeyStore_Release(&((*signer)->keyStore));
+ return true;
+}
+
+parcObject_ImplementAcquire(_mockSigner, _MockSigner);
+parcObject_ImplementRelease(_mockSigner, _MockSigner);
+
+parcObject_Override(_MockSigner, PARCObject,
+ .destructor = (PARCObjectDestructor *) _releaseSigner);
+
+static _MockSigner *
+_createSigner()
+{
+ const char *filename = "/tmp/test_ecdsa.p12";
+ const char *password = "12345";
+ const char *subject = "alice";
+ _MockSigner *signer = parcObject_CreateInstance(_MockSigner);
+
+ signer->hasher = parcCryptoHasher_Create(PARCCryptoHashType_SHA256);
+
+ bool res = parcPkcs12KeyStore_CreateFile(filename, password, subject, PARCSigningAlgorithm_ECDSA, 256, 180);
+ assertTrue(res, "Unable to create an ECDSA key");
+
+ PARCPkcs12KeyStore *publicKeyStore = parcPkcs12KeyStore_Open("test_ec.p12", "blueberry", PARCCryptoHashType_SHA256);
+
+ assertNotNull(publicKeyStore, "Got null result from opening openssl pkcs12 file");
+
+ signer->keyStore = parcKeyStore_Create(publicKeyStore, PARCPkcs12KeyStoreAsKeyStore);
+ parcPkcs12KeyStore_Release(&publicKeyStore);
+
+ return signer;
+}
+
+static PARCSigningInterface *_MockSignerInterface = &(PARCSigningInterface) {
+ .GetCryptoHasher = (PARCCryptoHasher * (*)(void *))_GetCryptoHasher,
+ .SignDigest = (PARCSignature * (*)(void *, const PARCCryptoHash *))_SignDigest,
+ .GetSigningAlgorithm = (PARCSigningAlgorithm (*)(void *))_GetSigningAlgorithm,
+ .GetCryptoHashType = (PARCCryptoHashType (*)(void *))_GetCryptoHashType,
+ .GetKeyStore = (PARCKeyStore * (*)(void *))_GetKeyStore,
+};
+
+LONGBOW_TEST_RUNNER(parc_Signer)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_Signer)
+{
+ 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_Signer)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_CreateKeyId);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_CreatePublicKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_GetCryptoHasher);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_SignDigest);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_GetSigningAlgorithm);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_GetCryptoHashType);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigner_GetKeyStore);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ 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(Global, parcSigner_Create)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+ _mockSigner_Release(&mock);
+
+ assertNotNull(signer, "Expected non-null signer");
+
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_AcquireRelease)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+ _mockSigner_Release(&mock);
+
+ assertNotNull(signer, "Expected non-null signer");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcSigner_Acquire, signer);
+
+ parcSigner_Release(&signer);
+ assertNull(signer, "Expected null result from parcSigner_Release();");
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_CreateKeyId)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+ _mockSigner_Release(&mock);
+
+ PARCKeyId *keyId = parcSigner_CreateKeyId(signer);
+
+ assertNotNull(keyId, "Expected non-NULL PARCKeyId");
+
+ parcKeyId_Release(&keyId);
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_CreatePublicKey)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+
+ PARCKey *key = parcSigner_CreatePublicKey(signer);
+
+ // Compute the real value
+ PARCCryptoHash *hash = parcKeyStore_GetVerifierKeyDigest(mock->keyStore);
+ PARCKeyId *keyid = parcKeyId_Create(parcCryptoHash_GetDigest(hash));
+ PARCBuffer *derEncodedKey = parcKeyStore_GetDEREncodedPublicKey(mock->keyStore);
+
+ PARCKey *expectedKey = parcKey_CreateFromDerEncodedPublicKey(keyid,
+ parcSigner_GetSigningAlgorithm(signer),
+ derEncodedKey);
+
+ parcBuffer_Release(&derEncodedKey);
+ parcKeyId_Release(&keyid);
+
+ parcCryptoHash_Release(&hash);
+
+ assertTrue(parcKey_Equals(key, expectedKey), "Expected public keys to be computed equally.");
+
+ parcKey_Release(&key);
+ parcKey_Release(&expectedKey);
+ parcSigner_Release(&signer);
+ _mockSigner_Release(&mock);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_GetCryptoHasher)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+ _mockSigner_Release(&mock);
+
+ PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer);
+
+ assertNotNull(hasher, "Expected non-NULL PARCCryptoHasher");
+
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_SignDigest)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+ _mockSigner_Release(&mock);
+
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ PARCCryptoHash *hash = parcCryptoHash_Create(PARCCryptoHashType_SHA256, buffer);
+ PARCSignature *signature = parcSigner_SignDigest(signer, hash);
+
+ assertNotNull(signature, "Expected non-NULL PARCSignature");
+
+ PARCBuffer *bits = parcSignature_GetSignature(signature);
+ char *bitstring = parcBuffer_ToString(bits);
+ char *expectedString = FAKE_SIGNATURE;
+ assertTrue(strcmp(bitstring, expectedString) == 0, "Expected the forced signature as output %s, got %s", expectedString, bitstring);
+ parcMemory_Deallocate(&bitstring);
+
+ parcCryptoHash_Release(&hash);
+ parcBuffer_Release(&buffer);
+ parcSignature_Release(&signature);
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_GetSigningAlgorithm)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+ _mockSigner_Release(&mock);
+
+ PARCSigningAlgorithm alg = parcSigner_GetSigningAlgorithm(signer);
+ assertTrue(PARCSigningAlgorithm_ECDSA == alg, "Expected PARCSigningAlgorithm_ECDSA algorithm, got %d", alg);
+
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_GetCryptoHashType)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+ _mockSigner_Release(&mock);
+
+ PARCCryptoHashType type = parcSigner_GetCryptoHashType(signer);
+ assertTrue(PARCCryptoHashType_SHA256 == type, "Expected PARCCryptoHashType_SHA256 algorithm, got %d", type);
+
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigner_GetKeyStore)
+{
+ _MockSigner *mock = _createSigner();
+ PARCSigner *signer = parcSigner_Create(mock, _MockSignerInterface);
+ _mockSigner_Release(&mock);
+
+ PARCKeyStore *keyStore = parcSigner_GetKeyStore(signer);
+ assertNotNull(keyStore, "Expected non-NULL PARCKeyStore");
+
+ parcSigner_Release(&signer);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_Signer);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_SigningAlgorithm.c b/libparc/parc/security/test/test_parc_SigningAlgorithm.c
new file mode 100755
index 00000000..12e50956
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_SigningAlgorithm.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_SigningAlgorithm.c"
+#include <parc/security/parc_CryptoSuite.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+LONGBOW_TEST_RUNNER(test_parc_SigningAlgorithm)
+{
+ // 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_parc_SigningAlgorithm)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_SigningAlgorithm)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcSigningAlgorithm_ToFromString);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigningAlgorithm_ToFromString_NotFound);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigningAlgorithm_GetSigningAlgorithm);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigningAlgorithm_FromString_NotFound);
+ LONGBOW_RUN_TEST_CASE(Global, parcSigningAlgorithm_GetSigningAlgorithm_BadAlgorithm);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcSigningAlgorithm_ToFromString)
+{
+ PARCSigningAlgorithm expected = PARCSigningAlgorithm_HMAC;
+
+ const char *string = parcSigningAlgorithm_ToString(expected);
+
+ PARCSigningAlgorithm actual = parcSigningAlgorithm_FromString(string);
+
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcSigningAlgorithm_ToFromString_NotFound)
+{
+ PARCSigningAlgorithm expected = 123456;
+
+ const char *string = parcSigningAlgorithm_ToString(expected);
+
+ assertNull(string, "Expect parcSigningAlgorithm_ToString to return NULL");
+}
+
+LONGBOW_TEST_CASE(Global, parcSigningAlgorithm_FromString_NotFound)
+{
+ PARCSigningAlgorithm actual = parcSigningAlgorithm_FromString("garbage string of unknown stuff");
+
+ assertTrue(actual == PARCSigningAlgorithm_UNKNOWN,
+ "Expect parcSigningAlgorithm_FromString to return PARCSigningAlgorithm_UNKNOWN");
+}
+
+LONGBOW_TEST_CASE(Global, parcSigningAlgorithm_GetSigningAlgorithm)
+{
+ PARCSigningAlgorithm actual = parcCryptoSuite_GetSigningAlgorithm(PARCCryptoSuite_DSA_SHA256);
+ assertTrue(PARCSigningAlgorithm_DSA == actual, "Expected %d, actual %d", PARCSigningAlgorithm_DSA, actual);
+
+ actual = parcCryptoSuite_GetSigningAlgorithm(PARCCryptoSuite_RSA_SHA256);
+ assertTrue(PARCSigningAlgorithm_RSA == actual, "Expected %d, actual %d", PARCSigningAlgorithm_RSA, actual);
+
+ actual = parcCryptoSuite_GetSigningAlgorithm(PARCCryptoSuite_RSA_SHA512);
+ assertTrue(PARCSigningAlgorithm_RSA == actual, "Expected %d, actual %d", PARCSigningAlgorithm_RSA, actual);
+
+ actual = parcCryptoSuite_GetSigningAlgorithm(PARCCryptoSuite_HMAC_SHA256);
+ assertTrue(PARCSigningAlgorithm_HMAC == actual, "Expected %d, actual %d", PARCSigningAlgorithm_HMAC, actual);
+
+ actual = parcCryptoSuite_GetSigningAlgorithm(PARCCryptoSuite_HMAC_SHA512);
+ assertTrue(PARCSigningAlgorithm_HMAC == actual, "Expected %d, actual %d", PARCSigningAlgorithm_HMAC, actual);
+
+ actual = parcCryptoSuite_GetSigningAlgorithm(PARCCryptoSuite_NULL_CRC32C);
+ assertTrue(PARCSigningAlgorithm_NULL == actual, "Expected %d, actual %d", PARCSigningAlgorithm_NULL, actual);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcSigningAlgorithm_GetSigningAlgorithm_BadAlgorithm, .event = &LongBowTrapIllegalValue)
+{
+ parcCryptoSuite_GetSigningAlgorithm(-1);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_SigningAlgorithm);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_SymmetricKeySigner.c b/libparc/parc/security/test/test_parc_SymmetricKeySigner.c
new file mode 100644
index 00000000..44b169eb
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_SymmetricKeySigner.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 "../parc_SymmetricKeySigner.c"
+#include <sys/param.h>
+
+#include <errno.h>
+#include <config.h>
+#include <fcntl.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+#include <LongBow/longBow_Compiler.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>
+
+static PARCSymmetricKeySigner *
+_createSigner()
+{
+ PARCBuffer *secret_key = parcSymmetricKeyStore_CreateKey(256);
+
+ PARCSymmetricKeyStore *symmetricKeyStore = parcSymmetricKeyStore_Create(secret_key);
+ parcBuffer_Release(&secret_key);
+
+ PARCSymmetricKeySigner *privateKeySigner = parcSymmetricKeySigner_Create(symmetricKeyStore, PARCCryptoHashType_SHA256);
+ parcSymmetricKeyStore_Release(&symmetricKeyStore);
+
+ return privateKeySigner;
+}
+
+LONGBOW_TEST_RUNNER(parc_SymmetricSigner)
+{
+ // 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(Specialization);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_SymmetricSigner)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_SymmetricSigner)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateAcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(CreateAcquireRelease, CreateRelease);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateAcquireRelease)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ 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)
+{
+ PARCSymmetricKeySigner *instance = _createSigner();
+
+ assertNotNull(instance, "Expected non-null result from parcSymmetricKeySigner_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcSymmetricKeySigner_Acquire, instance);
+
+ parcSymmetricKeySigner_Release(&instance);
+ assertNull(instance, "Expected null result from parcSymmetricKeySigner_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, test_hmac_sha256);
+ LONGBOW_RUN_TEST_CASE(Specialization, test_hmac_sha512);
+}
+
+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, test_hmac_sha256)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_CTX *ctx = HMAC_CTX_new();
+#else
+ HMAC_CTX ctx;
+#endif
+ char key[] = "apple_pie_is_good";
+ int fd;
+ uint8_t to_digest_buffer[MAXPATHLEN];
+ ssize_t to_digest_length;
+
+ uint8_t true_hmac_buffer[MAXPATHLEN];
+ ssize_t true_hmac_length;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_Init_ex(ctx, key, sizeof(key), EVP_sha256(), NULL);
+#else
+ LONGBOW_STOP_DEPRECATED_WARNINGS
+ HMAC_CTX_init(&ctx);
+ HMAC_Init_ex(&ctx, key, sizeof(key), EVP_sha256(), NULL);
+ LONGBOW_START_DEPRECATED_WARNINGS
+#endif
+ fd = open("test_random_bytes", O_RDONLY);
+ assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
+ to_digest_length = read(fd, to_digest_buffer, sizeof(to_digest_buffer));
+ assertTrue(to_digest_length > 0, "Could not read input file: %s", strerror(errno));
+ close(fd);
+
+ fd = open("test_random_bytes.hmac_sha256", O_RDONLY);
+ assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
+ true_hmac_length = read(fd, true_hmac_buffer, sizeof(true_hmac_buffer));
+ assertTrue(true_hmac_length > 0, "Could not read input file: %s", strerror(errno));
+ close(fd);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ _hmacInit(ctx);
+ _hmacUpdate(ctx, to_digest_buffer, to_digest_length);
+ PARCBuffer *output = _hmacFinalize(ctx);
+#else
+ _hmacInit(&ctx);
+ _hmacUpdate(&ctx, to_digest_buffer, to_digest_length);
+ PARCBuffer *output = _hmacFinalize(&ctx);
+#endif
+
+ assertTrue(parcBuffer_Position(output) == true_hmac_length,
+ "hmac wrong length, expected %zu got %zu",
+ true_hmac_length,
+ parcBuffer_Position(output));
+
+ assertTrue(memcmp(parcByteArray_Array(parcBuffer_Array(output)), true_hmac_buffer, true_hmac_length) == 0,
+ "hmac values did not match");
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_CTX_free(ctx);
+#else
+ LONGBOW_STOP_DEPRECATED_WARNINGS
+ HMAC_cleanup(&ctx);
+ LONGBOW_START_DEPRECATED_WARNINGS
+#endif
+ parcBuffer_Release(&output);
+}
+
+LONGBOW_TEST_CASE(Specialization, test_hmac_sha512)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_CTX *ctx = HMAC_CTX_new();
+#else
+ HMAC_CTX ctx;
+#endif
+ char key[] = "apple_pie_is_good";
+ int fd;
+ uint8_t to_digest_buffer[MAXPATHLEN];
+ ssize_t to_digest_length;
+
+ uint8_t true_hmac_buffer[MAXPATHLEN];
+ ssize_t true_hmac_length;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_Init_ex(ctx, key, sizeof(key), EVP_sha512(), NULL);
+#else
+ LONGBOW_STOP_DEPRECATED_WARNINGS
+ HMAC_CTX_init(&ctx);
+ HMAC_Init_ex(&ctx, key, sizeof(key), EVP_sha512(), NULL);
+ LONGBOW_START_DEPRECATED_WARNINGS
+#endif
+ fd = open("test_random_bytes", O_RDONLY);
+ assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
+ to_digest_length = read(fd, to_digest_buffer, sizeof(to_digest_buffer));
+ assertTrue(to_digest_length > 0, "Could not read input file: %s", strerror(errno));
+ close(fd);
+
+ fd = open("test_random_bytes.hmac_sha512", O_RDONLY);
+ assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
+ true_hmac_length = read(fd, true_hmac_buffer, sizeof(true_hmac_buffer));
+ assertTrue(true_hmac_length > 0, "Could not read input file: %s", strerror(errno));
+ close(fd);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ _hmacInit(ctx);
+ _hmacUpdate(ctx, to_digest_buffer, to_digest_length);
+ PARCBuffer *output = _hmacFinalize(ctx);
+#else
+ _hmacInit(&ctx);
+ _hmacUpdate(&ctx, to_digest_buffer, to_digest_length);
+ PARCBuffer *output = _hmacFinalize(&ctx);
+#endif
+
+ assertTrue(parcBuffer_Position(output) == true_hmac_length,
+ "hmac wrong length, expected %zu got %zu",
+ true_hmac_length,
+ parcBuffer_Position(output));
+
+ assertTrue(memcmp(parcByteArray_Array(parcBuffer_Array(output)), true_hmac_buffer, true_hmac_length) == 0,
+ "hmac values did not match");
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_CTX_free(ctx);
+#else
+ LONGBOW_STOP_DEPRECATED_WARNINGS
+ HMAC_cleanup(&ctx);
+ LONGBOW_START_DEPRECATED_WARNINGS
+#endif
+ parcBuffer_Release(&output);
+}
+
+LONGBOW_TEST_CASE(Global, parcSymmetricSigner_SignatureSize)
+{
+ PARCSymmetricKeySigner *symmetricSigner = _createSigner();
+
+ PARCSigner *signer = parcSigner_Create(symmetricSigner, PARCSymmetricKeySignerAsSigner);
+
+ assertTrue(parcSigner_GetSignatureSize(signer) == 32, "Key size unexpected %d ", parcSigner_GetSignatureSize(signer));
+ parcSigner_Release(&signer);
+ parcSymmetricKeySigner_Release(&symmetricSigner);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_SymmetricSigner);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_SymmetricKeyStore.c b/libparc/parc/security/test/test_parc_SymmetricKeyStore.c
new file mode 100755
index 00000000..ab9dfddb
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_SymmetricKeyStore.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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_SymmetricKeyStore.c"
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <errno.h>
+#include <sys/param.h>
+#include <fcntl.h>
+
+#include <parc/security/parc_SymmetricKeySigner.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_SymmetricSignerFileStore)
+{
+ // 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(parc_SymmetricSignerFileStore)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_SymmetricSignerFileStore)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcSymmetricKeyStore_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcSymmetricKeyStore_CreateKey);
+// LONGBOW_RUN_TEST_CASE(Global, parcSymmetricKeyStore_CreateFail);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ 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(Global, parcSymmetricKeyStore_Create)
+{
+ char dirname[] = "/tmp/pubkeystore_XXXXXX";
+ char filename[MAXPATHLEN];
+
+ char *tmp_dirname = mkdtemp(dirname);
+ assertNotNull(tmp_dirname, "tmp_dirname should not be null");
+ sprintf(filename, "%s/pubkeystore.p12", tmp_dirname);
+
+ PARCBuffer *secret_key = parcSymmetricKeyStore_CreateKey(256);
+
+ PARCSymmetricKeyStore *symmetricKeyStore = parcSymmetricKeyStore_Create(secret_key);
+ PARCSymmetricKeySigner *privateKeySigner = parcSymmetricKeySigner_Create(symmetricKeyStore, PARCCryptoHashType_SHA256);
+ PARCSigner *signer = parcSigner_Create(privateKeySigner, PARCSymmetricKeySignerAsSigner);
+ parcSymmetricKeySigner_Release(&privateKeySigner);
+
+ parcSymmetricKeyStore_Release(&symmetricKeyStore);
+ parcSigner_Release(&signer);
+ parcBuffer_Release(&secret_key);
+}
+
+LONGBOW_TEST_CASE(Global, parcSymmetricKeyStore_CreateKey)
+{
+ PARCBuffer *bb = parcSymmetricKeyStore_CreateKey(256);
+ assertTrue(parcBuffer_Remaining(bb) == 32, "Key wrong length expected %d got %zu", 32, parcBuffer_Position(bb));
+ parcBuffer_Release(&bb);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, parcSymmetricKeyStore_CreateFail, .event = &LongBowTrapIllegalValue)
+{
+ PARCBuffer *key = parcSymmetricKeyStore_CreateKey(256);
+ PARCSymmetricKeyStore *symmetricKeyStore = parcSymmetricKeyStore_Create(key);
+ PARCSymmetricKeySigner *privateKeySigner = parcSymmetricKeySigner_Create(symmetricKeyStore, PARCCryptoHashType_CRC32C);
+
+ // fail.
+
+ parcSymmetricKeyStore_Release(&symmetricKeyStore);
+ parcSymmetricKeySigner_Release(&privateKeySigner);
+ parcBuffer_Release(&key);
+}
+
+// ==========================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, parcSymmetricKeyStore_GetCryptoHashType);
+ LONGBOW_RUN_TEST_CASE(Local, parcSymmetricKeyStore_GetSecretKeyDigest);
+ LONGBOW_RUN_TEST_CASE(Local, parcSymmetricKeyStore_GetSigningAlgorithm);
+ LONGBOW_RUN_TEST_CASE(Local, parcSymmetricKeyStore_SignDigest_sha256);
+ LONGBOW_RUN_TEST_CASE(Local, parcSymmetricKeyStore_SignDigest_sha512);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ 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, parcSymmetricKeyStore_GetCryptoHashType)
+{
+ PARCBuffer *secret_key = parcSymmetricKeyStore_CreateKey(256);
+
+ PARCSymmetricKeyStore *symmetricKeyStore = parcSymmetricKeyStore_Create(secret_key);
+ PARCSymmetricKeySigner *privateKeySigner = parcSymmetricKeySigner_Create(symmetricKeyStore, PARCCryptoHashType_SHA256);
+ PARCSigner *signer = parcSigner_Create(privateKeySigner, PARCSymmetricKeySignerAsSigner);
+ parcSymmetricKeySigner_Release(&privateKeySigner);
+
+ PARCCryptoHashType hashType = parcSigner_GetCryptoHashType(signer);
+ assertTrue(hashType == PARCCryptoHashType_SHA256,
+ "Got wrong hash Type, expected %d got %d", PARCCryptoHashType_SHA256, hashType);
+
+ parcSymmetricKeyStore_Release(&symmetricKeyStore);
+ parcSigner_Release(&signer);
+ parcBuffer_Release(&secret_key);
+}
+
+LONGBOW_TEST_CASE(Local, parcSymmetricKeyStore_GetSecretKeyDigest)
+{
+ int fd;
+ uint8_t key_buffer[128];
+ uint8_t key_sha256[128];
+ ssize_t read_len;
+
+ fd = open("test_symmetric_key.bin", O_RDONLY);
+ read_len = read(fd, key_buffer, sizeof(key_buffer));
+ assertTrue(read_len == 32, "read wrong size, expected 32, got %zd", read_len);
+ close(fd);
+
+ fd = open("test_symmetric_key.sha256", O_RDONLY);
+ read_len = read(fd, key_sha256, sizeof(key_sha256));
+ assertTrue(read_len == 32, "read wrong size, expected 32, got %zd", read_len);
+ close(fd);
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer, key_buffer, 32);
+ PARCBuffer *secret_key = parcBufferComposer_ProduceBuffer(composer);
+
+ PARCBufferComposer *composer2 = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer2, key_sha256, 32);
+ PARCBuffer *secret_sha = parcBufferComposer_ProduceBuffer(composer2);
+
+ PARCSymmetricKeyStore *symmetricKeyStore = parcSymmetricKeyStore_Create(secret_key);
+ PARCSymmetricKeySigner *privateKeySigner = parcSymmetricKeySigner_Create(symmetricKeyStore, PARCCryptoHashType_SHA256);
+ PARCSigner *signer = parcSigner_Create(privateKeySigner, PARCSymmetricKeySignerAsSigner);
+ parcSymmetricKeySigner_Release(&privateKeySigner);
+
+ PARCCryptoHash *key_hash = parcKeyStore_GetVerifierKeyDigest(parcSigner_GetKeyStore(signer));
+ assertTrue(parcBuffer_Equals(parcCryptoHash_GetDigest(key_hash), secret_sha),
+ "sha256 digests of secret key did not match");
+ parcCryptoHash_Release(&key_hash);
+
+ parcSymmetricKeyStore_Release(&symmetricKeyStore);
+ parcBuffer_Release(&secret_sha);
+ parcBufferComposer_Release(&composer);
+ parcBuffer_Release(&secret_key);
+ parcBufferComposer_Release(&composer2);
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Local, parcSymmetricKeyStore_GetSigningAlgorithm)
+{
+ PARCBuffer *secret_key = parcSymmetricKeyStore_CreateKey(256);
+
+ PARCSymmetricKeyStore *symmetricKeyStore = parcSymmetricKeyStore_Create(secret_key);
+ PARCSymmetricKeySigner *privateKeySigner = parcSymmetricKeySigner_Create(symmetricKeyStore, PARCCryptoHashType_SHA256);
+ PARCSigner *signer = parcSigner_Create(privateKeySigner, PARCSymmetricKeySignerAsSigner);
+ parcSymmetricKeySigner_Release(&privateKeySigner);
+
+ PARCSigningAlgorithm alg = parcSigner_GetSigningAlgorithm(signer);
+ assertTrue(alg == PARCSigningAlgorithm_HMAC,
+ "Got wrong signing algorithm, expected %d got %d", PARCSigningAlgorithm_HMAC, alg);
+
+ parcSymmetricKeyStore_Release(&symmetricKeyStore);
+ parcSigner_Release(&signer);
+ parcBuffer_Release(&secret_key);
+}
+
+LONGBOW_TEST_CASE(Local, parcSymmetricKeyStore_SignDigest_sha256)
+{
+ uint8_t to_digest_buffer[MAXPATHLEN];
+ ssize_t to_digest_length;
+ uint8_t true_hmac_buffer[MAXPATHLEN];
+ char key[] = "apple_pie_is_good";
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, key);
+ PARCBuffer *key_buffer = parcBufferComposer_ProduceBuffer(composer);
+
+ int fd = open("test_random_bytes", O_RDONLY);
+ assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
+ to_digest_length = read(fd, to_digest_buffer, sizeof(to_digest_buffer));
+ assertTrue(to_digest_length > 0, "Could not read input file: %s", strerror(errno));
+ close(fd);
+
+ fd = open("test_random_bytes.hmac_sha256", O_RDONLY);
+ assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
+ ssize_t true_hmac_length = read(fd, true_hmac_buffer, sizeof(true_hmac_buffer));
+ assertTrue(true_hmac_length > 0, "Could not read input file: %s", strerror(errno));
+ close(fd);
+
+ PARCBufferComposer *composer2 = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer2, true_hmac_buffer, true_hmac_length);
+ PARCBuffer *true_hash = parcBufferComposer_ProduceBuffer(composer2);
+
+ PARCSymmetricKeyStore *symmetricKeyStore = parcSymmetricKeyStore_Create(key_buffer);
+ PARCSymmetricKeySigner *privateKeySigner = parcSymmetricKeySigner_Create(symmetricKeyStore, PARCCryptoHashType_SHA256);
+ PARCSigner *signer = parcSigner_Create(privateKeySigner, PARCSymmetricKeySignerAsSigner);
+ parcSymmetricKeySigner_Release(&privateKeySigner);
+
+ PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBytes(hasher, to_digest_buffer, to_digest_length);
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+ PARCSignature *sig = parcSigner_SignDigest(signer, hash);
+
+ assertTrue(parcBuffer_Equals(parcSignature_GetSignature(sig), parcCryptoHash_GetDigest(hash)),
+ "Hashes are not equal");
+ assertTrue(parcBuffer_Equals(parcSignature_GetSignature(sig), true_hash),
+ "Hash does not match file");
+ assertTrue(parcSignature_GetSigningAlgorithm(sig) == PARCSigningAlgorithm_HMAC,
+ "Signing alg incorrect, expected %d got %d",
+ PARCSigningAlgorithm_HMAC, parcSignature_GetSigningAlgorithm(sig));
+ assertTrue(parcSignature_GetHashType(sig) == PARCCryptoHashType_SHA256,
+ "Digest alg incorrect, expected %d got %d",
+ PARCCryptoHashType_SHA256, parcSignature_GetSigningAlgorithm(sig));
+
+ parcSymmetricKeyStore_Release(&symmetricKeyStore);
+ parcSignature_Release(&sig);
+ parcCryptoHash_Release(&hash);
+ parcBuffer_Release(&true_hash);
+ parcBuffer_Release(&key_buffer);
+ parcBufferComposer_Release(&composer);
+ parcBufferComposer_Release(&composer2);
+ parcSigner_Release(&signer);
+}
+
+LONGBOW_TEST_CASE(Local, parcSymmetricKeyStore_SignDigest_sha512)
+{
+ char key[] = "apple_pie_is_good";
+
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+ parcBufferComposer_PutString(composer, key);
+ PARCBuffer *key_buffer = parcBufferComposer_ProduceBuffer(composer);
+
+ int fd;
+ uint8_t to_digest_buffer[MAXPATHLEN];
+ ssize_t to_digest_length;
+
+ uint8_t true_hmac_buffer[MAXPATHLEN];
+ ssize_t true_hmac_length;
+
+ fd = open("test_random_bytes", O_RDONLY);
+ assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
+ to_digest_length = read(fd, to_digest_buffer, sizeof(to_digest_buffer));
+ assertTrue(to_digest_length > 0, "Could not read input file: %s", strerror(errno));
+ close(fd);
+
+ fd = open("test_random_bytes.hmac_sha512", O_RDONLY);
+ assertTrue(fd > 0, "Could not open input file: %s", strerror(errno));
+ true_hmac_length = read(fd, true_hmac_buffer, sizeof(true_hmac_buffer));
+ assertTrue(true_hmac_length > 0, "Could not read input file: %s", strerror(errno));
+ close(fd);
+
+ PARCBufferComposer *composer2 = parcBufferComposer_Create();
+ parcBufferComposer_PutArray(composer2, true_hmac_buffer, true_hmac_length);
+ PARCBuffer *true_hash = parcBufferComposer_ProduceBuffer(composer2);
+
+ PARCSymmetricKeyStore *symmetricKeyStore = parcSymmetricKeyStore_Create(key_buffer);
+ PARCSymmetricKeySigner *privateKeySigner = parcSymmetricKeySigner_Create(symmetricKeyStore, PARCCryptoHashType_SHA512);
+ PARCSigner *signer = parcSigner_Create(privateKeySigner, PARCSymmetricKeySignerAsSigner);
+ parcSymmetricKeySigner_Release(&privateKeySigner);
+
+ PARCCryptoHasher *hasher = parcSigner_GetCryptoHasher(signer);
+ parcCryptoHasher_Init(hasher);
+ parcCryptoHasher_UpdateBytes(hasher, to_digest_buffer, to_digest_length);
+ PARCCryptoHash *hash = parcCryptoHasher_Finalize(hasher);
+ PARCSignature *sig = parcSigner_SignDigest(signer, hash);
+
+ assertTrue(parcBuffer_Equals(parcSignature_GetSignature(sig), parcCryptoHash_GetDigest(hash)),
+ "Hashes are not equal");
+ assertTrue(parcBuffer_Equals(parcSignature_GetSignature(sig), true_hash),
+ "Hash does not match file");
+ assertTrue(parcSignature_GetSigningAlgorithm(sig) == PARCSigningAlgorithm_HMAC,
+ "Signing alg incorrect, expected %d got %d",
+ PARCSigningAlgorithm_HMAC, parcSignature_GetSigningAlgorithm(sig));
+ assertTrue(parcSignature_GetHashType(sig) == PARCCryptoHashType_SHA512,
+ "Digest alg incorrect, expected %d got %d",
+ PARCCryptoHashType_SHA512, parcSignature_GetSigningAlgorithm(sig));
+
+ parcSymmetricKeyStore_Release(&symmetricKeyStore);
+ parcSignature_Release(&sig);
+ parcCryptoHash_Release(&hash);
+ parcBuffer_Release(&true_hash);
+ parcBuffer_Release(&key_buffer);
+ parcBufferComposer_Release(&composer);
+ parcBufferComposer_Release(&composer2);
+ parcSigner_Release(&signer);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_SymmetricSignerFileStore);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_Verifier.c b/libparc/parc/security/test/test_parc_Verifier.c
new file mode 100755
index 00000000..fe382a9b
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_Verifier.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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Verifier.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_Verifier)
+{
+ // 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(parc_Verifier)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_Verifier)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcVerifier_AddKey);
+ LONGBOW_RUN_TEST_CASE(Global, parcVerifier_AllowedCryptoSuite);
+ LONGBOW_RUN_TEST_CASE(Global, parcVerifier_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcVerifier_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, parcVerifier_GetCryptoHasher);
+ LONGBOW_RUN_TEST_CASE(Global, parcVerifier_RemoveKeyId);
+ LONGBOW_RUN_TEST_CASE(Global, parcVerifier_VerifySignature);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcVerifier_AddKey)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcVerifier_AllowedCryptoSuite)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcVerifier_Create)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcVerifier_Destroy)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcVerifier_GetCryptoHasher)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcVerifier_RemoveKeyId)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, parcVerifier_VerifySignature)
+{
+ testUnimplemented("");
+}
+
+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(parc_Verifier);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_parc_X509Certificate.c b/libparc/parc/security/test/test_parc_X509Certificate.c
new file mode 100755
index 00000000..dda9a9ff
--- /dev/null
+++ b/libparc/parc/security/test/test_parc_X509Certificate.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <unistd.h>
+#include <fcntl.h>
+
+#include "../parc_X509Certificate.c"
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/algol/parc_Buffer.h>
+
+LONGBOW_TEST_RUNNER(parc_X509Certificate)
+{
+ // 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_TEST_RUNNER_SETUP(parc_X509Certificate)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_X509Certificate)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_CreateFromDERBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_GetPublicKeyDigest);
+ LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_GetCertificateDigest);
+ LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_GetDEREncodedCertificate);
+ LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_GetDEREncodedPublicKey);
+ LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_CreateSelfSignedCertificate_RSA);
+ LONGBOW_RUN_TEST_CASE(Global, parc_X509Certificate_CreateSelfSignedCertificate_EC);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ parcSecurity_Init();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ 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(Global, parc_X509Certificate_AcquireRelease)
+{
+ char *fileName = "test.pem";
+ PARCX509Certificate *certificate = parcX509Certificate_CreateFromPEMFile(fileName);
+ assertNotNull(certificate, "Expected non-NULL certificate");
+
+ PARCReferenceCount firstCount = parcObject_GetReferenceCount(certificate);
+ PARCX509Certificate *copy = parcX509Certificate_Acquire(certificate);
+ PARCReferenceCount secondCount = parcObject_GetReferenceCount(copy);
+
+ assertTrue(firstCount == (secondCount - 1), "Expected incremented reference count after Acquire");
+
+ parcX509Certificate_Release(&copy);
+ PARCReferenceCount thirdCount = parcObject_GetReferenceCount(certificate);
+
+ assertTrue(firstCount == thirdCount, "Expected equal reference counts after Release");
+
+ parcX509Certificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_X509Certificate_Create)
+{
+ char *fileName = "bad.pem";
+ PARCX509Certificate *certificate = _parcX509Certificate_CreateFromPEMFile(fileName);
+ assertNull(certificate, "Expected NULL certificate with non-existent file");
+}
+
+LONGBOW_TEST_CASE(Global, parc_X509Certificate_CreateSelfSignedCertificate_EC)
+{
+ PARCBuffer *privateKeyBuffer = NULL;
+ PARCX509Certificate *certificate = _createSelfSignedCertificate_EC(&privateKeyBuffer, "TEST", 256, 180);
+ assertNotNull(certificate, "Expected non-NULL EC certificate");
+ parcBuffer_Release(&privateKeyBuffer);
+ parcX509Certificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_X509Certificate_CreateSelfSignedCertificate_RSA)
+{
+ PARCBuffer *privateKeyBuffer = NULL;
+ PARCX509Certificate *certificate = _createSelfSignedCertificate_RSA(&privateKeyBuffer, "TEST", 1024, 180);
+ assertNotNull(certificate, "Expected non-NULL RSA certificate");
+ parcBuffer_Release(&privateKeyBuffer);
+ parcX509Certificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_X509Certificate_CreateFromDERBuffer)
+{
+ char *fileName = "test.pem";
+ PARCX509Certificate *certificate = _parcX509Certificate_CreateFromPEMFile(fileName);
+ assertNotNull(certificate, "Expected non-NULL certificate");
+
+ PARCBuffer *certificateBuffer = _getDEREncodedCertificate(certificate);
+ PARCX509Certificate *realCertificate = parcX509Certificate_CreateFromDERBuffer(certificateBuffer);
+ assertNotNull(realCertificate, "Expected non-NULL certificate to be parsed from DER buffer");
+
+ parcX509Certificate_Release(&certificate);
+ parcX509Certificate_Release(&realCertificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_X509Certificate_GetPublicKeyDigest)
+{
+ char *fileName = "test.pem";
+ PARCX509Certificate *certificate = _parcX509Certificate_CreateFromPEMFile(fileName);
+
+ PARCCryptoHash *digest = _getPublicKeyDigest(certificate);
+ PARCBuffer *digestBuffer = parcCryptoHash_GetDigest(digest);
+
+ size_t expectedLength = SHA256_DIGEST_LENGTH;
+ size_t actualLength = parcBuffer_Remaining(digestBuffer);
+ assertTrue(actualLength == expectedLength, "Digest unexpected size: got %zu expected %zu", actualLength, expectedLength);
+
+ int fd = open("test_pubkey.bin", O_RDONLY);
+ uint8_t rawDigest[SHA256_DIGEST_LENGTH];
+ ssize_t numBytes = read(fd, rawDigest, SHA256_DIGEST_LENGTH);
+ assertTrue(numBytes == SHA256_DIGEST_LENGTH, "Expected to read %d bytes, got %zu", SHA256_DIGEST_LENGTH, numBytes);
+ close(fd);
+
+ PARCBuffer *rawBuffer = parcBuffer_Flip(parcBuffer_CreateFromArray(rawDigest, SHA256_DIGEST_LENGTH));
+
+ assertTrue(parcBuffer_Remaining(rawBuffer) == SHA256_DIGEST_LENGTH, "Expected %d length buffer", SHA256_DIGEST_LENGTH);
+
+ parcBuffer_Release(&rawBuffer);
+ parcX509Certificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_X509Certificate_GetCertificateDigest)
+{
+ char *fileName = "test.pem";
+ PARCX509Certificate *certificate = _parcX509Certificate_CreateFromPEMFile(fileName);
+
+ PARCCryptoHash *digest = _getCertificateDigest(certificate);
+ PARCBuffer *digestBuffer = parcCryptoHash_GetDigest(digest);
+
+ size_t expectedLength = SHA256_DIGEST_LENGTH;
+ size_t actualLength = parcBuffer_Remaining(digestBuffer);
+ assertTrue(actualLength == expectedLength, "Digest unexpected size: got %zu expected %zu", actualLength, expectedLength);
+
+ int fd = open("test_crt_sha256.bin", O_RDONLY);
+ uint8_t rawDigest[SHA256_DIGEST_LENGTH];
+ ssize_t numBytes = read(fd, rawDigest, SHA256_DIGEST_LENGTH);
+ assertTrue(numBytes == SHA256_DIGEST_LENGTH, "Expected to read %d bytes, got %zu", SHA256_DIGEST_LENGTH, numBytes);
+ close(fd);
+
+ PARCBuffer *rawBuffer = parcBuffer_Flip(parcBuffer_CreateFromArray(rawDigest, SHA256_DIGEST_LENGTH));
+
+ assertTrue(parcBuffer_Equals(rawBuffer, digestBuffer), "Expected raw binary to equal the computed result.");
+
+ parcBuffer_Release(&rawBuffer);
+ parcX509Certificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_X509Certificate_GetDEREncodedCertificate)
+{
+ char *fileName = "test.pem";
+ PARCX509Certificate *certificate = _parcX509Certificate_CreateFromPEMFile(fileName);
+
+ PARCBuffer *digestBuffer = _getDEREncodedCertificate(certificate);
+
+ size_t expectedLength = 517;
+ size_t actualLength = parcBuffer_Remaining(digestBuffer);
+ assertTrue(actualLength == expectedLength, "Digest unexpected size: got %zu expected %zu", actualLength, expectedLength);
+
+ int fd = open("test_crt_der.bin", O_RDONLY);
+ uint8_t rawDigest[expectedLength];
+ ssize_t numBytes = read(fd, rawDigest, expectedLength);
+ assertTrue(numBytes == expectedLength, "Expected to read %zu bytes, got %zu", expectedLength, numBytes);
+ close(fd);
+
+ PARCBuffer *rawBuffer = parcBuffer_Flip(parcBuffer_CreateFromArray(rawDigest, expectedLength));
+
+ assertTrue(parcBuffer_Equals(rawBuffer, digestBuffer), "Expected raw binary to equal the computed result.");
+
+ parcBuffer_Release(&rawBuffer);
+ parcX509Certificate_Release(&certificate);
+}
+
+LONGBOW_TEST_CASE(Global, parc_X509Certificate_GetDEREncodedPublicKey)
+{
+ char *fileName = "test.pem";
+ PARCX509Certificate *certificate = _parcX509Certificate_CreateFromPEMFile(fileName);
+
+ PARCBuffer *digestBuffer = _getDEREncodedPublicKey(certificate);
+
+ size_t expectedLength = 162;
+ size_t actualLength = parcBuffer_Remaining(digestBuffer);
+ assertTrue(actualLength == expectedLength, "Digest unexpected size: got %zu expected %zu", actualLength, expectedLength);
+
+ int fd = open("test_der.bin", O_RDONLY);
+ uint8_t rawDigest[expectedLength];
+ ssize_t numBytes = read(fd, rawDigest, expectedLength);
+ assertTrue(numBytes == expectedLength, "Expected to read %zu bytes, got %zu", expectedLength, numBytes);
+ close(fd);
+
+ PARCBuffer *rawBuffer = parcBuffer_Flip(parcBuffer_CreateFromArray(rawDigest, expectedLength));
+
+ assertTrue(parcBuffer_Equals(rawBuffer, digestBuffer), "Expected raw binary to equal the computed result.");
+
+ parcBuffer_Release(&rawBuffer);
+ parcX509Certificate_Release(&certificate);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_X509Certificate);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/security/test/test_pubkey.bin b/libparc/parc/security/test/test_pubkey.bin
new file mode 100644
index 00000000..1d426b87
--- /dev/null
+++ b/libparc/parc/security/test/test_pubkey.bin
@@ -0,0 +1 @@
+_.yWSföÓØÞbQ½äИ6º¡uôš\áåobŠ§ \ No newline at end of file
diff --git a/libparc/parc/security/test/test_pubkey.der b/libparc/parc/security/test/test_pubkey.der
new file mode 100644
index 00000000..eb75e987
--- /dev/null
+++ b/libparc/parc/security/test/test_pubkey.der
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDR0t1wjPPlx/x3vMDN/yaClXmp
+NqdIX31oejG4nFQrqH821a6vZjaEEk6jNUM9v4a5mDHdgXQCvSjoRVnfCPVi06j/
+h4oylHaANMSOfcP2AimGBT0R1mT8cBHsI1JmYfhS5jSCzxyyTtq0WVDqndGl0qZp
+cRGONepOxn36uZso2QIDAQAB
+-----END PUBLIC KEY-----
diff --git a/libparc/parc/security/test/test_pubkey.pem b/libparc/parc/security/test/test_pubkey.pem
new file mode 100644
index 00000000..eb75e987
--- /dev/null
+++ b/libparc/parc/security/test/test_pubkey.pem
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDR0t1wjPPlx/x3vMDN/yaClXmp
+NqdIX31oejG4nFQrqH821a6vZjaEEk6jNUM9v4a5mDHdgXQCvSjoRVnfCPVi06j/
+h4oylHaANMSOfcP2AimGBT0R1mT8cBHsI1JmYfhS5jSCzxyyTtq0WVDqndGl0qZp
+cRGONepOxn36uZso2QIDAQAB
+-----END PUBLIC KEY-----
diff --git a/libparc/parc/security/test/test_random_bytes b/libparc/parc/security/test/test_random_bytes
new file mode 100644
index 00000000..33a80af5
--- /dev/null
+++ b/libparc/parc/security/test/test_random_bytes
Binary files differ
diff --git a/libparc/parc/security/test/test_random_bytes.hmac_sha256 b/libparc/parc/security/test/test_random_bytes.hmac_sha256
new file mode 100644
index 00000000..ee066075
--- /dev/null
+++ b/libparc/parc/security/test/test_random_bytes.hmac_sha256
Binary files differ
diff --git a/libparc/parc/security/test/test_random_bytes.hmac_sha512 b/libparc/parc/security/test/test_random_bytes.hmac_sha512
new file mode 100644
index 00000000..fcd110b2
--- /dev/null
+++ b/libparc/parc/security/test/test_random_bytes.hmac_sha512
Binary files differ
diff --git a/libparc/parc/security/test/test_random_bytes.sig b/libparc/parc/security/test/test_random_bytes.sig
new file mode 100644
index 00000000..9c395ce0
--- /dev/null
+++ b/libparc/parc/security/test/test_random_bytes.sig
Binary files differ
diff --git a/libparc/parc/security/test/test_random_bytes.sig_ec b/libparc/parc/security/test/test_random_bytes.sig_ec
new file mode 100644
index 00000000..92b210a1
--- /dev/null
+++ b/libparc/parc/security/test/test_random_bytes.sig_ec
Binary files differ
diff --git a/libparc/parc/security/test/test_rsa.crt b/libparc/parc/security/test/test_rsa.crt
new file mode 100644
index 00000000..6f7ce9e6
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa.crt
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICATCCAWoCCQDE2fTij4zOkTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
+VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMB4XDTEzMTAxNTIzMjUyNloXDTE0MTAxNTIzMjUyNlowRTELMAkG
+A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAp9aT
+xfFzxhK1+nnF7xiL76rNBAGPg3c/sWahWrk5KrI+MPsR/Ff8ndEvd/Crd61mLCbI
+m1Fvab8mEAYp7suwLF6RDiRCjeZ1oE4EQww+TAZ0Z62Ew+j0xZRzxJ8lqEIGv0UZ
+4pgcNqFDTZtxCOGC3+JPKjw9DzWSrnAn+9LkHicCAwEAATANBgkqhkiG9w0BAQUF
+AAOBgQALNQ1/nNF/jMYijV+XI/IL0/zziaUu2GSyTQlGsmfLhMY0/Qx+8Pbaik+R
+DVtNMZatJGSXgSvx6ETGpkXVdsZzZfDIYSIyKrbf7uV3GFfqCv4IqU2OI42ex7TE
+Ry+xm2mioAYgcnAIxA4CmyTm+tWJ9MTJkCG/aPhhcPxP6XzjPA==
+-----END CERTIFICATE-----
diff --git a/libparc/parc/security/test/test_rsa.csr b/libparc/parc/security/test/test_rsa.csr
new file mode 100644
index 00000000..1ff56fc4
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa.csr
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIBhDCB7gIBADBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh
+MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQCn1pPF8XPGErX6ecXvGIvvqs0EAY+Ddz+xZqFauTkqsj4w
++xH8V/yd0S938Kt3rWYsJsibUW9pvyYQBinuy7AsXpEOJEKN5nWgTgRDDD5MBnRn
+rYTD6PTFlHPEnyWoQga/RRnimBw2oUNNm3EI4YLf4k8qPD0PNZKucCf70uQeJwID
+AQABoAAwDQYJKoZIhvcNAQEFBQADgYEAEVdzGyNxqWTRSaBo8JybmHNuXiTLvGPR
+GCegG3GwtTiptzwrtUhOmkWoPkWBwB/rLJyga7sPgg73D5aCz3PsagNSqLytCuW+
+qFJdODd6IXQrJ8fUHsV2SENNbkL+zsg1cYVB0T+8B6BP84hHaD3NResmMVjhuPIr
+0uHYQ7e2ex8=
+-----END CERTIFICATE REQUEST-----
diff --git a/libparc/parc/security/test/test_rsa.p12 b/libparc/parc/security/test/test_rsa.p12
new file mode 100644
index 00000000..471c4006
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa.p12
Binary files differ
diff --git a/libparc/parc/security/test/test_rsa_crt.der b/libparc/parc/security/test/test_rsa_crt.der
new file mode 100644
index 00000000..d79f4b47
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa_crt.der
Binary files differ
diff --git a/libparc/parc/security/test/test_rsa_crt_sha256.bin b/libparc/parc/security/test/test_rsa_crt_sha256.bin
new file mode 100644
index 00000000..7da092ff
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa_crt_sha256.bin
@@ -0,0 +1,2 @@
+VFé,ž-x(S¸º‚ßEl/š
+:óH&è6¥4M!:¦=) \ No newline at end of file
diff --git a/libparc/parc/security/test/test_rsa_key.der b/libparc/parc/security/test/test_rsa_key.der
new file mode 100644
index 00000000..a88e8e94
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa_key.der
Binary files differ
diff --git a/libparc/parc/security/test/test_rsa_key.pem b/libparc/parc/security/test/test_rsa_key.pem
new file mode 100644
index 00000000..6c502b15
--- /dev/null
+++ b/libparc/parc/security/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/libparc/parc/security/test/test_rsa_pub.der b/libparc/parc/security/test/test_rsa_pub.der
new file mode 100644
index 00000000..7c931999
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa_pub.der
Binary files differ
diff --git a/libparc/parc/security/test/test_rsa_pub.pem b/libparc/parc/security/test/test_rsa_pub.pem
new file mode 100644
index 00000000..7b8f29c2
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa_pub.pem
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn1pPF8XPGErX6ecXvGIvvqs0E
+AY+Ddz+xZqFauTkqsj4w+xH8V/yd0S938Kt3rWYsJsibUW9pvyYQBinuy7AsXpEO
+JEKN5nWgTgRDDD5MBnRnrYTD6PTFlHPEnyWoQga/RRnimBw2oUNNm3EI4YLf4k8q
+PD0PNZKucCf70uQeJwIDAQAB
+-----END PUBLIC KEY-----
diff --git a/libparc/parc/security/test/test_rsa_pub_sha256.bin b/libparc/parc/security/test/test_rsa_pub_sha256.bin
new file mode 100644
index 00000000..c15478cf
--- /dev/null
+++ b/libparc/parc/security/test/test_rsa_pub_sha256.bin
@@ -0,0 +1 @@
+\#L(PÚ {ˆ%‹óba–Øð`v8¢ÔàâI²©¯Î¸…Y \ No newline at end of file
diff --git a/libparc/parc/security/test/test_symmetric_key.bin b/libparc/parc/security/test/test_symmetric_key.bin
new file mode 100644
index 00000000..2ad3409d
--- /dev/null
+++ b/libparc/parc/security/test/test_symmetric_key.bin
Binary files differ
diff --git a/libparc/parc/security/test/test_symmetric_key.sha256 b/libparc/parc/security/test/test_symmetric_key.sha256
new file mode 100644
index 00000000..910397cf
--- /dev/null
+++ b/libparc/parc/security/test/test_symmetric_key.sha256
@@ -0,0 +1 @@
+A—ê_ÖöèÓ»¨§-;‡ÈèßÈn.ï1 ~í072 \ No newline at end of file
diff --git a/libparc/parc/statistics/parc_BasicStats.c b/libparc/parc/statistics/parc_BasicStats.c
new file mode 100644
index 00000000..b66bbd7a
--- /dev/null
+++ b/libparc/parc/statistics/parc_BasicStats.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <math.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/statistics/parc_BasicStats.h>
+
+struct PARCBasicStats {
+ int64_t count;
+ double maximum;
+ double minimum;
+ double mean;
+ double variance;
+};
+
+static inline bool
+_parcBasicStats_FloatEquals(double x, double y, double e)
+{
+ return fabs(x - y) < e;
+}
+
+static bool
+_parcBasicStats_Destructor(PARCBasicStats **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCBasicStats pointer.");
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcBasicStats, PARCBasicStats);
+
+parcObject_ImplementRelease(parcBasicStats, PARCBasicStats);
+
+parcObject_Override(
+ PARCBasicStats, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcBasicStats_Destructor,
+ .copy = (PARCObjectCopy *) parcBasicStats_Copy,
+ .toString = (PARCObjectToString *) parcBasicStats_ToString,
+ .equals = (PARCObjectEquals *) parcBasicStats_Equals,
+ .compare = (PARCObjectCompare *) parcBasicStats_Compare,
+ .hashCode = (PARCObjectHashCode *) parcBasicStats_HashCode,
+ .toJSON = (PARCObjectToJSON *) parcBasicStats_ToJSON);
+
+
+void
+parcBasicStats_AssertValid(const PARCBasicStats *instance)
+{
+ assertTrue(parcBasicStats_IsValid(instance),
+ "PARCBasicStats is not valid.");
+}
+
+
+PARCBasicStats *
+parcBasicStats_Create(void)
+{
+ PARCBasicStats *result = parcObject_CreateInstance(PARCBasicStats);
+
+ if (result != NULL) {
+ result->count = 0;
+ result->mean = 0;
+ result->variance = 0;
+ result->maximum = 0;
+ result->minimum = 0;
+ }
+
+ return result;
+}
+
+int
+parcBasicStats_Compare(const PARCBasicStats *instance, const PARCBasicStats *other)
+{
+ int result = 0;
+
+ return result;
+}
+
+PARCBasicStats *
+parcBasicStats_Copy(const PARCBasicStats *original)
+{
+ PARCBasicStats *result = parcBasicStats_Create();
+ result->count = original->count;
+ result->mean = original->mean;
+ result->variance = original->variance;
+ result->maximum = original->maximum;
+ result->minimum = original->minimum;
+
+ return result;
+}
+
+void
+parcBasicStats_Display(const PARCBasicStats *stats, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation,
+ "PARCBasicStats@%p { .count=%" PRId64 " .minimum=%llf .maximum=%llf .mean=%llf }",
+ stats, stats->count, stats->minimum, stats->maximum, stats->mean);
+}
+
+bool
+parcBasicStats_Equals(const PARCBasicStats *x, const PARCBasicStats *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (x->count == y->count) {
+ if (_parcBasicStats_FloatEquals(x->maximum, y->maximum, 0.00001)) {
+ if (_parcBasicStats_FloatEquals(x->minimum, y->minimum, 0.00001)) {
+ if (_parcBasicStats_FloatEquals(x->mean, y->mean, 0.00001)) {
+ result = true;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcBasicStats_HashCode(const PARCBasicStats *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+parcBasicStats_IsValid(const PARCBasicStats *stats)
+{
+ bool result = false;
+
+ if (stats != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcBasicStats_ToJSON(const PARCBasicStats *stats)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ if (result != NULL) {
+ PARCJSONPair *pair = parcJSONPair_CreateFromDouble("maximum", stats->maximum);
+ parcJSON_AddPair(result, pair);
+ parcJSONPair_Release(&pair);
+
+ pair = parcJSONPair_CreateFromDouble("minimum", stats->minimum);
+ parcJSON_AddPair(result, pair);
+ parcJSONPair_Release(&pair);
+
+ pair = parcJSONPair_CreateFromDouble("mean", stats->mean);
+ parcJSON_AddPair(result, pair);
+ parcJSONPair_Release(&pair);
+
+ pair = parcJSONPair_CreateFromDouble("variance", stats->variance);
+ parcJSON_AddPair(result, pair);
+ parcJSONPair_Release(&pair);
+
+ pair = parcJSONPair_CreateFromInteger("count", stats->count);
+ parcJSON_AddPair(result, pair);
+ parcJSONPair_Release(&pair);
+ }
+
+ return result;
+}
+
+char *
+parcBasicStats_ToString(const PARCBasicStats *stats)
+{
+ char *result = parcMemory_Format("PARCBasicStats@%p { .count=%" PRId64 " .minimum=%llf .maximum=%llf .mean=%llf }",
+ stats, stats->count, stats->minimum, stats->maximum, stats->mean);
+
+ return result;
+}
+
+void
+parcBasicStats_Update(PARCBasicStats *stats, double value)
+{
+ stats->count++;
+
+ if (value > stats->maximum) {
+ stats->maximum = value;
+ }
+
+ if (value < stats->minimum) {
+ stats->minimum = value;
+ }
+
+ double mean_ = stats->mean;
+
+ double xMinusOldMean = value - mean_;
+
+ stats->mean = mean_ + xMinusOldMean / stats->count;
+
+ double xMinusCurrentMean = value - stats->mean;
+
+ stats->variance = ((stats->variance * (stats->count - 1)) + xMinusOldMean * xMinusCurrentMean) / stats->count;
+}
+
+double
+parcBasicStats_Mean(const PARCBasicStats *stats)
+{
+ return stats->mean;
+}
+
+double
+parcBasicStats_Variance(const PARCBasicStats *stats)
+{
+ return stats->variance;
+}
+
+double
+parcBasicStats_StandardDeviation(const PARCBasicStats *stats)
+{
+ return sqrt(stats->variance);
+}
+
+double
+parcBasicStats_Maximum(const PARCBasicStats *stats)
+{
+ return stats->maximum;
+}
+
+double
+parcBasicStats_Minimum(const PARCBasicStats *stats)
+{
+ return stats->minimum;
+}
+
+double
+parcBasicStats_Range(const PARCBasicStats *stats)
+{
+ return stats->maximum - stats->minimum;
+}
diff --git a/libparc/parc/statistics/parc_BasicStats.h b/libparc/parc/statistics/parc_BasicStats.h
new file mode 100755
index 00000000..5f82e582
--- /dev/null
+++ b/libparc/parc/statistics/parc_BasicStats.h
@@ -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.
+ */
+
+/**
+ * @file parc_BasicStats.h
+ * @ingroup statistics
+ * @brief A basic descriptive statistics implementation for time-series data.
+ *
+ */
+#ifndef PARCLIbrary_parc_IntegerStats
+#define PARCLIbrary_parc_IntegerStats
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+struct PARCBasicStats;
+typedef struct PARCBasicStats PARCBasicStats;
+
+/**
+ * Increase the number of references to a `PARCBasicStats` instance.
+ *
+ * Note that new `PARCBasicStats` is not created,
+ * only that the given `PARCBasicStats` reference count is incremented.
+ * Discard the reference by invoking `parcBasicStats_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCBasicStats instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBasicStats *a = parcBasicStats_Create();
+ *
+ * PARCBasicStats *b = parcBasicStats_Acquire();
+ *
+ * parcBasicStats_Release(&a);
+ * parcBasicStats_Release(&b);
+ * }
+ * @endcode
+ */
+PARCBasicStats *parcBasicStats_Acquire(const PARCBasicStats *instance);
+
+#ifdef PARCLIbrary_DISABLE_VALIDATION
+# define parcBasicStats_OptionalAssertValid(_instance_)
+#else
+# define parcBasicStats_OptionalAssertValid(_instance_) parcBasicStats_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCBasicStats` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCBasicStats instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBasicStats *a = parcBasicStats_Create();
+ *
+ * parcBasicStats_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcBasicStats_Release(&b);
+ * }
+ * @endcode
+ */
+void parcBasicStats_AssertValid(const PARCBasicStats *instance);
+
+/**
+ * Create an instance of PARCBasicStats
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @return non-NULL A pointer to a valid PARCBasicStats instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBasicStats *a = parcBasicStats_Create();
+ *
+ * parcBasicStats_Release(&a);
+ * }
+ * @endcode
+ */
+PARCBasicStats *parcBasicStats_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 PARCBasicStats instance.
+ * @param [in] other A pointer to a valid PARCBasicStats 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
+ * {
+ * PARCBasicStats *a = parcBasicStats_Create();
+ * PARCBasicStats *b = parcBasicStats_Create();
+ *
+ * if (parcBasicStats_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcBasicStats_Release(&a);
+ * parcBasicStats_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcBasicStats_Equals
+ */
+int parcBasicStats_Compare(const PARCBasicStats *instance, const PARCBasicStats *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 PARCBasicStats instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCBasicStats` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBasicStats *a = parcBasicStats_Create();
+ *
+ * PARCBasicStats *copy = parcBasicStats_Copy(&b);
+ *
+ * parcBasicStats_Release(&b);
+ * parcBasicStats_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCBasicStats *parcBasicStats_Copy(const PARCBasicStats *original);
+
+/**
+ * Print a human readable representation of the given `PARCBasicStats`.
+ *
+ * @param [in] instance A pointer to a valid PARCBasicStats instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBasicStats *a = parcBasicStats_Create();
+ *
+ * parcBasicStats_Display(a, 0);
+ *
+ * parcBasicStats_Release(&a);
+ * }
+ * @endcode
+ */
+void parcBasicStats_Display(const PARCBasicStats *instance, int indentation);
+
+/**
+ * Determine if two `PARCBasicStats` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCBasicStats` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcBasicStats_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcBasicStats_Equals(x, y)` must return true if and only if
+ * `parcBasicStats_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcBasicStats_Equals(x, y)` returns true and
+ * `parcBasicStats_Equals(y, z)` returns true,
+ * then `parcBasicStats_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcBasicStats_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcBasicStats_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCBasicStats instance.
+ * @param [in] y A pointer to a valid PARCBasicStats instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBasicStats *a = parcBasicStats_Create();
+ * PARCBasicStats *b = parcBasicStats_Create();
+ *
+ * if (parcBasicStats_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcBasicStats_Release(&a);
+ * parcBasicStats_Release(&b);
+ * }
+ * @endcode
+ * @see parcBasicStats_HashCode
+ */
+bool parcBasicStats_Equals(const PARCBasicStats *x, const PARCBasicStats *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 parcBasicStats_Equals} method,
+ * then calling the {@link parcBasicStats_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 parcBasicStats_Equals} function,
+ * then calling the `parcBasicStats_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCBasicStats instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBasicStats *a = parcBasicStats_Create();
+ *
+ * PARCHashCode hashValue = parcBasicStats_HashCode(buffer);
+ * parcBasicStats_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcBasicStats_HashCode(const PARCBasicStats *instance);
+
+/**
+ * Determine if an instance of `PARCBasicStats` 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 PARCBasicStats instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCBasicStats *a = parcBasicStats_Create();
+ *
+ * if (parcBasicStats_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcBasicStats_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcBasicStats_IsValid(const PARCBasicStats *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCBasicStats` 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
+ * {
+ * PARCBasicStats *a = parcBasicStats_Create();
+ *
+ * parcBasicStats_Release(&a);
+ * }
+ * @endcode
+ */
+void parcBasicStats_Release(PARCBasicStats **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCBasicStats 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
+ * {
+ * PARCBasicStats *a = parcBasicStats_Create();
+ *
+ * PARCJSON *json = parcBasicStats_ToJSON(a);
+ *
+ * char *cString = parcJSON_ToString(json);
+ * printf("JSON representation: %s\n", cString);
+ *
+ * parcMemory_Deallocate(&cString);
+ * parcJSON_Release(&json);
+ *
+ * parcBasicStats_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcBasicStats_ToJSON(const PARCBasicStats *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCBasicStats`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCBasicStats 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
+ * {
+ * PARCBasicStats *a = parcBasicStats_Create();
+ *
+ * char *string = parcBasicStats_ToString(a);
+ *
+ * parcBasicStats_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcBasicStats_Display
+ */
+char *parcBasicStats_ToString(const PARCBasicStats *instance);
+
+/**
+ * Add a value to the observed set of values.
+ *
+ * @param [in] stats A pointer to a valid `PARCBasicStats` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcBasicStats_Update(PARCBasicStats *stats, double value);
+
+/**
+ * The arithmetic mean of the set of observed values.
+ *
+ * @param [in] stats A pointer to a valid `PARCBasicStats` instance.
+ *
+ * @return The arithmetic mean of the set of observed values.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+double parcBasicStats_Mean(const PARCBasicStats *stats);
+
+/**
+ * The variance of the set of observed values.
+ *
+ * @param [in] stats A pointer to a valid `PARCBasicStats` instance.
+ *
+ * @return The variance of the set of observed values.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+double parcBasicStats_Variance(const PARCBasicStats *stats);
+
+/**
+ * The standard deviation of the set of observed values.
+ *
+ * @param [in] stats A pointer to a valid `PARCBasicStats` instance.
+ *
+ * @return The standard deviation of the set of observed values.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+double parcBasicStats_StandardDeviation(const PARCBasicStats *stats);
+
+/**
+ * The maximum value of the set of observed values.
+ *
+ * @param [in] stats A pointer to a valid `PARCBasicStats` instance.
+ *
+ * @return The maximum value of the set of observed values.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+double parcBasicStats_Maximum(const PARCBasicStats *stats);
+
+/**
+ * The minimum value of the set of observed values.
+ *
+ * @param [in] stats A pointer to a valid `PARCBasicStats` instance.
+ *
+ * @return The minimum value of the set of observed values.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+double parcBasicStats_Minimum(const PARCBasicStats *stats);
+
+/**
+ * The arithmetic range of the observed set of values.
+ *
+ * @param [in] stats A pointer to a valid `PARCBasicStats` instance.
+ *
+ * @return The arithmetic range of the observed set of values.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+double parcBasicStats_Range(const PARCBasicStats *stats);
+#endif
diff --git a/libparc/parc/statistics/parc_EWMA.c b/libparc/parc/statistics/parc_EWMA.c
new file mode 100644
index 00000000..20f85d4a
--- /dev/null
+++ b/libparc/parc/statistics/parc_EWMA.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <math.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/statistics/parc_EWMA.h>
+
+struct PARCEWMA {
+ bool initialized;
+ int64_t value;
+ double coefficient;
+ double coefficient_r;
+};
+
+static inline bool
+_parcEWMA_FloatEquals(double x, double y, double e)
+{
+ return fabs(x - y) < e;
+}
+
+static bool
+_parcEWMA_Destructor(PARCEWMA **instancePtr)
+{
+ assertNotNull(instancePtr, "Parameter must be a non-null pointer to a PARCEWMA pointer.");
+
+ return true;
+}
+
+parcObject_ImplementAcquire(parcEWMA, PARCEWMA);
+
+parcObject_ImplementRelease(parcEWMA, PARCEWMA);
+
+parcObject_Override(
+ PARCEWMA, PARCObject,
+ .destructor = (PARCObjectDestructor *) _parcEWMA_Destructor,
+ .copy = (PARCObjectCopy *) parcEWMA_Copy,
+ .toString = (PARCObjectToString *) parcEWMA_ToString,
+ .equals = (PARCObjectEquals *) parcEWMA_Equals,
+ .compare = (PARCObjectCompare *) parcEWMA_Compare,
+ .hashCode = (PARCObjectHashCode *) parcEWMA_HashCode,
+ .toJSON = (PARCObjectToJSON *) parcEWMA_ToJSON);
+
+void
+parcEWMA_AssertValid(const PARCEWMA *instance)
+{
+ assertTrue(parcEWMA_IsValid(instance),
+ "PARCEWMA is not valid.");
+}
+
+PARCEWMA *
+parcEWMA_Create(double coefficient)
+{
+ PARCEWMA *result = parcObject_CreateInstance(PARCEWMA);
+ if (result != NULL) {
+ result->initialized = false;
+ result->value = 0;
+ result->coefficient = coefficient;
+ result->coefficient_r = 1.0 - coefficient;
+ }
+
+ return result;
+}
+
+int
+parcEWMA_Compare(const PARCEWMA *instance, const PARCEWMA *other)
+{
+ int result = 0;
+
+ if (instance == other) {
+ result = 0;
+ } else if (instance == NULL) {
+ result = -1;
+ } else if (other == NULL) {
+ result = 1;
+ } else {
+ result = instance->value - other->value;
+ }
+
+ return result;
+}
+
+PARCEWMA *
+parcEWMA_Copy(const PARCEWMA *original)
+{
+ PARCEWMA *result = parcEWMA_Create(original->coefficient);
+ result->initialized = original->initialized;
+ result->value = original->value;
+
+ return result;
+}
+
+void
+parcEWMA_Display(const PARCEWMA *ewma, int indentation)
+{
+ parcDisplayIndented_PrintLine(indentation,
+ "PARCEWMA@%p { .initialized=%s .coefficient=%lf, .value=%" PRId64 " }",
+ ewma,
+ ewma->initialized ? "true" : "false",
+ ewma->coefficient,
+ ewma->value);
+}
+
+bool
+parcEWMA_Equals(const PARCEWMA *x, const PARCEWMA *y)
+{
+ bool result = false;
+
+ if (x == y) {
+ result = true;
+ } else if (x == NULL || y == NULL) {
+ result = false;
+ } else {
+ if (x->initialized == y->initialized) {
+ if (_parcEWMA_FloatEquals(x->coefficient, y->coefficient, 0.00001)) {
+ if (_parcEWMA_FloatEquals(x->value, y->value, 0.00001)) {
+ result = true;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+PARCHashCode
+parcEWMA_HashCode(const PARCEWMA *instance)
+{
+ PARCHashCode result = 0;
+
+ return result;
+}
+
+bool
+parcEWMA_IsValid(const PARCEWMA *instance)
+{
+ bool result = false;
+
+ if (instance != NULL) {
+ result = true;
+ }
+
+ return result;
+}
+
+PARCJSON *
+parcEWMA_ToJSON(const PARCEWMA *instance)
+{
+ PARCJSON *result = parcJSON_Create();
+
+ if (result != NULL) {
+ }
+
+ return result;
+}
+
+char *
+parcEWMA_ToString(const PARCEWMA *ewma)
+{
+ char *result = parcMemory_Format("PARCEWMA@%p { .initialized=%s .coefficient=%lf, .value=%" PRId64 " }",
+ ewma,
+ ewma->initialized ? "true" : "false",
+ ewma->coefficient,
+ ewma->value);
+ return result;
+}
+
+int64_t
+parcEWMA_Update(PARCEWMA *ewma, const int64_t value)
+{
+ if (ewma->initialized) {
+ // E_t = a * V + (1 - a) * E_(t-1)
+ double x = (ewma->coefficient * value);
+ double y = (ewma->coefficient_r * ewma->value);
+
+ ewma->value = x + y;
+ } else {
+ ewma->value = value;
+ ewma->initialized = true;
+ }
+ return ewma->value;
+}
+
+int64_t
+parcEWMA_GetValue(const PARCEWMA *ewma)
+{
+ return ewma->value;
+}
diff --git a/libparc/parc/statistics/parc_EWMA.h b/libparc/parc/statistics/parc_EWMA.h
new file mode 100755
index 00000000..bbcb53df
--- /dev/null
+++ b/libparc/parc/statistics/parc_EWMA.h
@@ -0,0 +1,413 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 parc_EWMA.h
+ * @ingroup statistics
+ * @brief A simple exponential moving average smoothing filter for integers.
+ *
+ * An exponentially weighted moving average (EWMA) is a type of infinite impulse response filter that
+ * applies weighting factors which decrease exponentially. The weighting for each older datum decreases
+ * exponentially, never reaching zero.
+ *
+ */
+#ifndef PARCLibrary_parc_EWMA
+#define PARCLibrary_parc_EWMA
+#include <stdbool.h>
+
+#include <parc/algol/parc_JSON.h>
+#include <parc/algol/parc_HashCode.h>
+
+struct PARCEWMA;
+typedef struct PARCEWMA PARCEWMA;
+
+/**
+ * Increase the number of references to a `PARCEWMA` instance.
+ *
+ * Note that new `PARCEWMA` is not created,
+ * only that the given `PARCEWMA` reference count is incremented.
+ * Discard the reference by invoking `parcEWMA_Release`.
+ *
+ * @param [in] instance A pointer to a valid PARCEWMA instance.
+ *
+ * @return The same value as @p instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEWMA *a = parcEWMA_Create(0.75);
+ *
+ * PARCEWMA *b = parcEWMA_Acquire();
+ *
+ * parcEWMA_Release(&a);
+ * parcEWMA_Release(&b);
+ * }
+ * @endcode
+ */
+PARCEWMA *parcEWMA_Acquire(const PARCEWMA *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+# define parcEWMA_OptionalAssertValid(_instance_)
+#else
+# define parcEWMA_OptionalAssertValid(_instance_) parcEWMA_AssertValid(_instance_)
+#endif
+
+/**
+ * Assert that the given `PARCEWMA` instance is valid.
+ *
+ * @param [in] instance A pointer to a valid PARCEWMA instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEWMA *a = parcEWMA_Create(0.75);
+ *
+ * parcEWMA_AssertValid(a);
+ *
+ * printf("Instance is valid.\n");
+ *
+ * parcEWMA_Release(&b);
+ * }
+ * @endcode
+ */
+void parcEWMA_AssertValid(const PARCEWMA *instance);
+
+/**
+ * Create an instance of PARCEWMA
+ *
+ * The coefficient represents a constant smoothing factor affecting
+ * the degree of prior samples to be applied upon each new update.
+ * Typically the the coefficient is _0 < coefficient < 1.0_.
+ * A higher coefficient discounts older observations faster.
+ *
+ * @return non-NULL A pointer to a valid PARCEWMA instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEWMA *a = parcEWMA_Create(0.75);
+ *
+ * parcEWMA_Release(&a);
+ * }
+ * @endcode
+ */
+PARCEWMA *parcEWMA_Create(double coefficient);
+
+/**
+ * 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 PARCEWMA instance.
+ * @param [in] other A pointer to a valid PARCEWMA 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
+ * {
+ * PARCEWMA *a = parcEWMA_Create(0.75);
+ * PARCEWMA *b = parcEWMA_Create(0.75);
+ *
+ * if (parcEWMA_Compare(a, b) == 0) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcEWMA_Release(&a);
+ * parcEWMA_Release(&b);
+ * }
+ * @endcode
+ *
+ * @see parcEWMA_Equals
+ */
+int parcEWMA_Compare(const PARCEWMA *instance, const PARCEWMA *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 PARCEWMA instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a new `PARCEWMA` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEWMA *a = parcEWMA_Create(0.75);
+ *
+ * PARCEWMA *copy = parcEWMA_Copy(&b);
+ *
+ * parcEWMA_Release(&b);
+ * parcEWMA_Release(&copy);
+ * }
+ * @endcode
+ */
+PARCEWMA *parcEWMA_Copy(const PARCEWMA *original);
+
+/**
+ * Print a human readable representation of the given `PARCEWMA`.
+ *
+ * @param [in] instance A pointer to a valid PARCEWMA instance.
+ * @param [in] indentation The indentation level to use for printing.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEWMA *a = parcEWMA_Create(0.75);
+ *
+ * parcEWMA_Display(a, 0);
+ *
+ * parcEWMA_Release(&a);
+ * }
+ * @endcode
+ */
+void parcEWMA_Display(const PARCEWMA *instance, int indentation);
+
+/**
+ * Determine if two `PARCEWMA` instances are equal.
+ *
+ * The following equivalence relations on non-null `PARCEWMA` instances are maintained: *
+ * * It is reflexive: for any non-null reference value x, `parcEWMA_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `parcEWMA_Equals(x, y)` must return true if and only if
+ * `parcEWMA_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `parcEWMA_Equals(x, y)` returns true and
+ * `parcEWMA_Equals(y, z)` returns true,
+ * then `parcEWMA_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `parcEWMA_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `parcEWMA_Equals(x, NULL)` must return false.
+ *
+ * @param [in] x A pointer to a valid PARCEWMA instance.
+ * @param [in] y A pointer to a valid PARCEWMA instance.
+ *
+ * @return true The instances x and y are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEWMA *a = parcEWMA_Create(0.75);
+ * PARCEWMA *b = parcEWMA_Create(0.75);
+ *
+ * if (parcEWMA_Equals(a, b)) {
+ * printf("Instances are equal.\n");
+ * }
+ *
+ * parcEWMA_Release(&a);
+ * parcEWMA_Release(&b);
+ * }
+ * @endcode
+ * @see parcEWMA_HashCode
+ */
+bool parcEWMA_Equals(const PARCEWMA *x, const PARCEWMA *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 parcEWMA_Equals} method,
+ * then calling the {@link parcEWMA_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 parcEWMA_Equals} function,
+ * then calling the `parcEWMA_HashCode`
+ * method on each of the two objects must produce distinct integer results.
+ *
+ * @param [in] instance A pointer to a valid PARCEWMA instance.
+ *
+ * @return The hashcode for the given instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEWMA *a = parcEWMA_Create(0.75);
+ *
+ * PARCHashCode hashValue = parcEWMA_HashCode(buffer);
+ * parcEWMA_Release(&a);
+ * }
+ * @endcode
+ */
+PARCHashCode parcEWMA_HashCode(const PARCEWMA *instance);
+
+/**
+ * Determine if an instance of `PARCEWMA` 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 PARCEWMA instance.
+ *
+ * @return true The instance is valid.
+ * @return false The instance is not valid.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEWMA *a = parcEWMA_Create(0.75);
+ *
+ * if (parcEWMA_IsValid(a)) {
+ * printf("Instance is valid.\n");
+ * }
+ *
+ * parcEWMA_Release(&a);
+ * }
+ * @endcode
+ *
+ */
+bool parcEWMA_IsValid(const PARCEWMA *instance);
+
+/**
+ * Release a previously acquired reference to the given `PARCEWMA` 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
+ * {
+ * PARCEWMA *a = parcEWMA_Create(0.75);
+ *
+ * parcEWMA_Release(&a);
+ * }
+ * @endcode
+ */
+void parcEWMA_Release(PARCEWMA **instancePtr);
+
+/**
+ * Create a `PARCJSON` instance (representation) of the given object.
+ *
+ * @param [in] instance A pointer to a valid PARCEWMA 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
+ * {
+ * PARCEWMA *a = parcEWMA_Create(0.75);
+ *
+ * PARCJSON *json = parcEWMA_ToJSON(a);
+ *
+ * char *cString = parcJSON_ToString(json);
+ * printf("JSON representation: %s\n", cString);
+ *
+ * parcMemory_Deallocate(&string);
+ * parcJSON_Release(&json);
+ *
+ * parcEWMA_Release(&a);
+ * }
+ * @endcode
+ */
+PARCJSON *parcEWMA_ToJSON(const PARCEWMA *instance);
+
+/**
+ * Produce a null-terminated string representation of the specified `PARCEWMA`.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] instance A pointer to a valid PARCEWMA 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
+ * {
+ * PARCEWMA *a = parcEWMA_Create(0.75);
+ *
+ * char *string = parcEWMA_ToString(a);
+ *
+ * parcEWMA_Release(&a);
+ *
+ * parcMemory_Deallocate(&string);
+ * }
+ * @endcode
+ *
+ * @see parcEWMA_Display
+ */
+char *parcEWMA_ToString(const PARCEWMA *instance);
+
+/**
+ * Update the given `PARCEWMA` filter.
+ *
+ * The value of the filter is modified by the input of an updated value
+ *
+ * @param [in] ewma A pointer to a valid `PARCEWMA` instance.
+ *
+ * @return The current exponentitally smoothed value of the filter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEWMA *ewma = parcEWMA_Create(0.75);
+ *
+ * for (uint64_t i = 0; i < 10; i++) {
+ * parcEWMA_Update(ewma, i);
+ * }
+ *
+ * int64_t smoothedValue = parcEWMA_GetValue(ewma);
+ *
+ * parcEWMA_Release(&ewma);
+ * }
+ * @endcode
+ */
+int64_t parcEWMA_Update(PARCEWMA *ewma, const int64_t value);
+
+/**
+ * Get the current exponentitally smoothed value of the filter.
+ *
+ * @param [in] ewma A pointer to a valid `PARCEWMA` instance.
+ *
+ * @return The current exponentitally smoothed value of the filter.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCEWMA *ewma = parcEWMA_Create(0.75);
+ *
+ * for (uint64_t i = 0; i < 10; i++) {
+ * parcEWMA_Update(ewma, i);
+ * }
+ *
+ * int64_t smoothedValue = parcEWMA_GetValue(ewma);
+ *
+ * parcEWMA_Release(&ewma);
+ * }
+ * @endcode
+ */
+int64_t parcEWMA_GetValue(const PARCEWMA *ewma);
+#endif
diff --git a/libparc/parc/statistics/test/CMakeLists.txt b/libparc/parc/statistics/test/CMakeLists.txt
new file mode 100644
index 00000000..fde78d5b
--- /dev/null
+++ b/libparc/parc/statistics/test/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(TestsExpectedToPass
+ test_parc_BasicStats
+ test_parc_EWMA
+ )
+
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
+
diff --git a/libparc/parc/statistics/test/test_parc_BasicStats.c b/libparc/parc/statistics/test/test_parc_BasicStats.c
new file mode 100644
index 00000000..129e8317
--- /dev/null
+++ b/libparc/parc/statistics/test/test_parc_BasicStats.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ */
+#include "../parc_BasicStats.c"
+
+#include <inttypes.h>
+#include <math.h>
+
+#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(parc_BasicStats)
+{
+ // 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(parc_BasicStats)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_BasicStats)
+{
+ 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)
+{
+ PARCBasicStats *instance = parcBasicStats_Create();
+ assertNotNull(instance, "Expected non-null result from parcBasicStats_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcBasicStats_Acquire, instance);
+
+ parcBasicStats_Release(&instance);
+ assertNull(instance, "Expected null result from parcBasicStats_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcBasicStats_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, parcBasicStats_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, parcBasicStats_Display);
+ LONGBOW_RUN_TEST_CASE(Object, parcBasicStats_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcBasicStats_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcBasicStats_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcBasicStats_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcBasicStats_ToString);
+}
+
+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, parcBasicStats_Compare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Object, parcBasicStats_Copy)
+{
+ PARCBasicStats *instance = parcBasicStats_Create();
+ PARCBasicStats *copy = parcBasicStats_Copy(instance);
+ assertTrue(parcBasicStats_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcBasicStats_Release(&instance);
+ parcBasicStats_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Object, parcBasicStats_Display)
+{
+ PARCBasicStats *instance = parcBasicStats_Create();
+ parcBasicStats_Display(instance, 0);
+ parcBasicStats_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcBasicStats_Equals)
+{
+ PARCBasicStats *x = parcBasicStats_Create();
+ PARCBasicStats *y = parcBasicStats_Create();
+ PARCBasicStats *z = parcBasicStats_Create();
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcBasicStats_Release(&x);
+ parcBasicStats_Release(&y);
+ parcBasicStats_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Object, parcBasicStats_HashCode)
+{
+ PARCBasicStats *x = parcBasicStats_Create();
+ PARCBasicStats *y = parcBasicStats_Create();
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcBasicStats_Release(&x);
+ parcBasicStats_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Object, parcBasicStats_IsValid)
+{
+ PARCBasicStats *instance = parcBasicStats_Create();
+ assertTrue(parcBasicStats_IsValid(instance), "Expected parcBasicStats_Create to result in a valid instance.");
+
+ parcBasicStats_Release(&instance);
+ assertFalse(parcBasicStats_IsValid(instance), "Expected parcBasicStats_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcBasicStats_ToJSON)
+{
+ PARCBasicStats *instance = parcBasicStats_Create();
+
+ PARCJSON *json = parcBasicStats_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcBasicStats_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcBasicStats_ToString)
+{
+ PARCBasicStats *instance = parcBasicStats_Create();
+
+ char *string = parcBasicStats_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcBasicStats_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcBasicStats_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, parcBasicStats_Update);
+}
+
+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, parcBasicStats_Update)
+{
+ PARCBasicStats *stats = parcBasicStats_Create();
+
+ parcBasicStats_Update(stats, 1);
+ parcBasicStats_Update(stats, 2);
+ parcBasicStats_Update(stats, 3);
+ parcBasicStats_Update(stats, 4);
+ parcBasicStats_Update(stats, 5);
+ parcBasicStats_Update(stats, 6);
+ parcBasicStats_Update(stats, 7);
+ parcBasicStats_Update(stats, 8);
+ parcBasicStats_Update(stats, 9);
+ parcBasicStats_Update(stats, 10);
+
+ double expected = 5.500;
+ double actual = parcBasicStats_Mean(stats);
+ assertTrue(fabs(actual - expected) < 0.001, "Expected %lf actual %lf", expected, actual);
+
+ expected = 8.25;
+ double variance = parcBasicStats_Variance(stats);
+ assertTrue(fabs(variance - expected) < 0.01, "Expected %lf actual %lf", expected, variance);
+
+ expected = 2.872;
+ double stddev = parcBasicStats_StandardDeviation(stats);
+ assertTrue(fabs(stddev - expected) < 0.001, "Expected %lf actual %lf", expected, stddev);
+
+ parcBasicStats_Release(&stats);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_BasicStats);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libparc/parc/statistics/test/test_parc_EWMA.c b/libparc/parc/statistics/test/test_parc_EWMA.c
new file mode 100644
index 00000000..689f4704
--- /dev/null
+++ b/libparc/parc/statistics/test/test_parc_EWMA.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 "../parc_EWMA.c"
+#include <stdio.h>
+#include <inttypes.h>
+
+#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(parc_EWMA)
+{
+ // 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(parc_EWMA)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_EWMA)
+{
+ 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)
+{
+ PARCEWMA *instance = parcEWMA_Create(0.75);
+ assertNotNull(instance, "Expected non-null result from parcEWMA_Create();");
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcEWMA_Acquire, instance);
+
+ parcEWMA_Release(&instance);
+ assertNull(instance, "Expected null result from parcEWMA_Release();");
+}
+
+LONGBOW_TEST_FIXTURE(Object)
+{
+ LONGBOW_RUN_TEST_CASE(Object, parcEWMA_Compare);
+ LONGBOW_RUN_TEST_CASE(Object, parcEWMA_Copy);
+ LONGBOW_RUN_TEST_CASE(Object, parcEWMA_Display);
+ LONGBOW_RUN_TEST_CASE(Object, parcEWMA_Equals);
+ LONGBOW_RUN_TEST_CASE(Object, parcEWMA_HashCode);
+ LONGBOW_RUN_TEST_CASE(Object, parcEWMA_IsValid);
+ LONGBOW_RUN_TEST_CASE(Object, parcEWMA_ToJSON);
+ LONGBOW_RUN_TEST_CASE(Object, parcEWMA_ToString);
+}
+
+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, parcEWMA_Compare)
+{
+ PARCEWMA *ewma = parcEWMA_Create(0.75);
+ PARCEWMA *lesser = parcEWMA_Create(0.75);
+ PARCEWMA *greater = parcEWMA_Create(0.75);
+
+ parcEWMA_Update(ewma, 5);
+ parcEWMA_Update(lesser, 1);
+ parcEWMA_Update(greater, 10);
+
+ parcObjectTesting_AssertCompareToImpl((PARCObjectCompare *) parcEWMA_Compare,
+ ewma,
+ (const void *[]) { ewma, NULL },
+ (const void *[]) { lesser, NULL },
+ (const void *[]) { greater, NULL });
+
+ parcEWMA_Release(&ewma);
+ parcEWMA_Release(&lesser);
+ parcEWMA_Release(&greater);
+}
+
+LONGBOW_TEST_CASE(Object, parcEWMA_Copy)
+{
+ PARCEWMA *instance = parcEWMA_Create(0.75);
+ PARCEWMA *copy = parcEWMA_Copy(instance);
+ assertTrue(parcEWMA_Equals(instance, copy), "Expected the copy to be equal to the original");
+
+ parcEWMA_Release(&instance);
+ parcEWMA_Release(&copy);
+}
+
+LONGBOW_TEST_CASE(Object, parcEWMA_Display)
+{
+ PARCEWMA *instance = parcEWMA_Create(0.75);
+ parcEWMA_Display(instance, 0);
+ parcEWMA_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcEWMA_Equals)
+{
+ PARCEWMA *x = parcEWMA_Create(0.75);
+ PARCEWMA *y = parcEWMA_Create(0.75);
+ PARCEWMA *z = parcEWMA_Create(0.75);
+
+ parcObjectTesting_AssertEquals(x, y, z, NULL);
+
+ parcEWMA_Release(&x);
+ parcEWMA_Release(&y);
+ parcEWMA_Release(&z);
+}
+
+LONGBOW_TEST_CASE(Object, parcEWMA_HashCode)
+{
+ PARCEWMA *x = parcEWMA_Create(0.75);
+ PARCEWMA *y = parcEWMA_Create(0.75);
+
+ parcObjectTesting_AssertHashCode(x, y);
+
+ parcEWMA_Release(&x);
+ parcEWMA_Release(&y);
+}
+
+LONGBOW_TEST_CASE(Object, parcEWMA_IsValid)
+{
+ PARCEWMA *instance = parcEWMA_Create(0.75);
+ assertTrue(parcEWMA_IsValid(instance), "Expected parcEWMA_Create to result in a valid instance.");
+
+ parcEWMA_Release(&instance);
+ assertFalse(parcEWMA_IsValid(instance), "Expected parcEWMA_Release to result in an invalid instance.");
+}
+
+LONGBOW_TEST_CASE(Object, parcEWMA_ToJSON)
+{
+ PARCEWMA *instance = parcEWMA_Create(0.75);
+
+ PARCJSON *json = parcEWMA_ToJSON(instance);
+
+ parcJSON_Release(&json);
+
+ parcEWMA_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Object, parcEWMA_ToString)
+{
+ PARCEWMA *instance = parcEWMA_Create(0.75);
+
+ char *string = parcEWMA_ToString(instance);
+
+ assertNotNull(string, "Expected non-NULL result from parcEWMA_ToString");
+
+ parcMemory_Deallocate((void **) &string);
+ parcEWMA_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE(Specialization)
+{
+ LONGBOW_RUN_TEST_CASE(Specialization, parcEWMA_Update);
+ LONGBOW_RUN_TEST_CASE(Specialization, parcEWMA_GetValue);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Specialization)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Specialization, parcEWMA_Update)
+{
+ PARCEWMA *instance = parcEWMA_Create(0.25);
+
+ for (int64_t i = 0; i < 100; i++) {
+ int64_t value = parcEWMA_Update(instance, i);
+ printf("%" PRId64 " %" PRId64 " %" PRId64 "\n", value, i, value - i);
+ }
+
+ parcEWMA_Release(&instance);
+}
+
+LONGBOW_TEST_CASE(Specialization, parcEWMA_GetValue)
+{
+ PARCEWMA *instance = parcEWMA_Create(0.75);
+
+ parcEWMA_Update(instance, 0);
+
+ int64_t value = parcEWMA_GetValue(instance);
+
+ assertTrue(value == 0, "Expected 0, actual %" PRId64 "", value);
+
+ parcEWMA_Release(&instance);
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Specialization)
+{
+ if (!parcMemoryTesting_ExpectedOutstanding(0, "%s mismanaged memory.", longBowTestCase_GetFullName(testCase))) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_EWMA);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+
+
diff --git a/libparc/parc/testing/parc_MemoryTesting.c b/libparc/parc/testing/parc_MemoryTesting.c
new file mode 100755
index 00000000..9a7b49fa
--- /dev/null
+++ b/libparc/parc/testing/parc_MemoryTesting.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 <parc/testing/parc_MemoryTesting.h>
+#include <parc/algol/parc_Memory.h>
+
+bool
+parcMemoryTesting_ExpectedOutstanding(const uint32_t expected, const char *format, ...)
+{
+ bool result = true;
+
+ int allocationsLeaked = parcMemory_Outstanding() - expected;
+ if (allocationsLeaked != 0) {
+ va_list ap;
+ va_start(ap, format);
+ vprintf(format, ap);
+ va_end(ap);
+ if (allocationsLeaked < 0) {
+ printf(" (%d more allocations deallocated than allocated)\n", -allocationsLeaked);
+ } else {
+ printf(" (%d allocations not deallocated)\n", allocationsLeaked);
+ }
+ result = false;
+ }
+
+ return result;
+}
diff --git a/libparc/parc/testing/parc_MemoryTesting.h b/libparc/parc/testing/parc_MemoryTesting.h
new file mode 100755
index 00000000..32b139db
--- /dev/null
+++ b/libparc/parc/testing/parc_MemoryTesting.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 parc_TestingMemory.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef PARC_Library_parc_TestingMemory_h
+#define PARC_Library_parc_TestingMemory_h
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+/**
+ * Determine if the current number of memory allocations is equal to the specified number.
+ *
+ * @param [in] expected The expected number of outstanding allocations.
+ *
+ * @return true The expected number of outstanding allocations is equal to the actual outstanding allocations.
+ *
+ * Example:
+ * @code
+ * {
+ * parcMemoryTesting_ExpectedOutstanding(0, "%s memory leak", __func__);
+ * }
+ * @endcode
+ */
+bool parcMemoryTesting_ExpectedOutstanding(const uint32_t expected, const char *format, ...);
+#endif
diff --git a/libparc/parc/testing/parc_ObjectTesting.c b/libparc/parc/testing/parc_ObjectTesting.c
new file mode 100644
index 00000000..03fe2222
--- /dev/null
+++ b/libparc/parc/testing/parc_ObjectTesting.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 <config.h>
+#include <LongBow/runtime.h>
+#include <inttypes.h>
+
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_Memory.h>
+
+void
+parcObjectTesting_AssertAcquireReleaseContractImpl(void *(acquireFunction)(const PARCObject *), const PARCObject *instance)
+{
+ void *reference = acquireFunction(instance);
+ assertTrue(reference == instance, "Expected the acquire function to return the same instance pointer.");
+ parcObject_Release(&reference);
+ parcObjectTesting_AssertAcquireReleaseImpl(instance);
+}
+
+void
+parcObjectTesting_AssertAcquireReleaseImpl(const PARCObject *instance)
+{
+ PARCReferenceCount originalReferences = parcObject_GetReferenceCount(instance);
+
+ PARCObject *newReference = parcObject_Acquire(instance);
+
+ assertTrue(newReference == instance, "Expected the acquire function to return the same instance pointer.");
+
+ PARCReferenceCount currentReferences = parcObject_GetReferenceCount(instance);
+ assertTrue(currentReferences == (originalReferences + 1),
+ "Expected references to be %" PRIu64 ", actual %" PRIu64, (originalReferences + 1), currentReferences);
+
+ parcObject_Release(&newReference);
+ currentReferences = parcObject_GetReferenceCount(instance);
+ assertTrue(currentReferences == originalReferences,
+ "Expected references to be %" PRIu64 ", actual %" PRIu64, originalReferences, currentReferences);
+}
+
+static void
+_parcObjectTesting_AssertEquals(bool (*equalsFunction)(const void *a, const void *b), const void *x, const void *y, const void *z, va_list ap)
+{
+ assertNotNull(x, "The value of x cannot be NULL.");
+ assertNotNull(y, "The value of y cannot be NULL.");
+ assertNotNull(z, "The value of z cannot be NULL.");
+
+ assertFalse(x == y, "The value x cannot be the same as y");
+ assertFalse(x == z, "The value x cannot be the same as z");
+ assertFalse(y == z, "The value y cannot be the same as z");
+
+ assertTrue(equalsFunction(NULL, NULL), "Equality failed: Equals(NULL, NULL) must be true");
+
+ assertFalse(equalsFunction(x, NULL), "Equality failed: The value of x must not be Equal to NULL.");
+ assertFalse(equalsFunction(NULL, x), "Equality failed: NULL must not be equal to the value of x.");
+
+ assertTrue(equalsFunction(x, x), "Reflexive failed: for any non-null reference value x, equals(x, x) must return true.");
+
+ assertTrue(equalsFunction(x, y), "Equality failed: The values of x and y must be Equal.");
+ assertTrue(equalsFunction(x, z), "Equality failed: The values of x and z must be Equal.");
+
+ assertTrue(equalsFunction(x, y) == equalsFunction(y, x), "Symmetric equality failed: equals(x, y) == equals(y, x) must true.");
+
+ assertTrue((equalsFunction(x, y) == equalsFunction(y, z)) == equalsFunction(z, x),
+ "Transitive equality failed: equals(x, y) == equals(y, z) == equals(z, x) must true.");
+
+ int index = 0;
+ for (void *value = va_arg(ap, void *); value != 0; value = va_arg(ap, void *)) {
+ assertFalse(equalsFunction(x, value), "Value %d (@%p) must not be equal to x", index, value);
+ assertTrue(equalsFunction(x, value) == equalsFunction(value, x),
+ "Symmetric equality failed: equals(x, value) == equals(value, x) must true.");
+ index++;
+ }
+}
+
+void
+parcObjectTesting_AssertEquals(const PARCObject *x, const void *y, const void *z, ...)
+{
+ va_list ap;
+ va_start(ap, z);
+
+ _parcObjectTesting_AssertEquals((bool (*)(const void *, const void *))parcObject_Equals, x, y, z, ap);
+
+ assertTrue(parcObject_HashCode(x) == parcObject_HashCode(y),
+ "HashCode of x and y must be equal");
+ assertTrue(parcObject_HashCode(x) == parcObject_HashCode(z),
+ "HashCode of x and z must be equal");
+
+ va_end(ap);
+}
+
+void
+parcObjectTesting_AssertEqualsFunctionImpl(bool (*equalsFunction)(const void *a, const void *b), const void *x, const void *y, const void *z, ...)
+{
+ va_list ap;
+ va_start(ap, z);
+ _parcObjectTesting_AssertEquals(equalsFunction, x, y, z, ap);
+
+ va_end(ap);
+}
+
+bool
+parcObjectTesting_AssertCompareToImpl(int (*compareTo)(const void *a, const void *b),
+ const void *exemplar,
+ const void **equivalent,
+ const void **lesser,
+ const void **greater)
+{
+ assertNotNull(exemplar, "Parameter exemplar must not be NULL");
+ assertNotNull(equivalent, "Parameter equivalent must not be NULL");
+ assertNotNull(lesser, "Parameter less must not be NULL");
+ assertNotNull(greater, "Parameter greater must not be NULL");
+
+ assertTrue(compareTo(NULL, NULL) == 0, "Comparison of null values must be 0.");
+
+ assertTrue(compareTo(exemplar, NULL) > 0, "Comparison of a non-null value to a null value must be > 0.");
+
+ assertTrue(compareTo(NULL, exemplar) < 0, "Comparison of null value to a non-null value must be < 0.");
+
+ assertTrue(compareTo(exemplar, exemplar) == 0, "Comparison of a value to itself must == 0");
+
+ for (int i = 0; equivalent[i] != NULL; i++) {
+ assertTrue(compareTo(exemplar, equivalent[i]) == 0,
+ "Comparison of the value to equivalent[%d] must == 0", i);
+ assertTrue(compareTo(exemplar, equivalent[i]) == -compareTo(equivalent[i], exemplar),
+ "Requires sgn(compareTo(value, equivalent[%d])) == -sgn(equivalent[%d], value)", i, i);
+ }
+ for (int i = 0; lesser[i] != NULL; i++) {
+ assertTrue(compareTo(exemplar, lesser[i]) > 0,
+ "Compare of value to lesser[%d] must be > 0", i);
+ assertTrue(compareTo(exemplar, lesser[i]) == -compareTo(lesser[i], exemplar),
+ "Requires signum(compareTo(value, lesser[%d])) == -signum(lesser[%d], value)", i, i);
+ }
+ for (int i = 0; greater[i] != NULL; i++) {
+ assertTrue(compareTo(exemplar, greater[i]) < 0, "Compare to greater[%d] must be > 0", i);
+ assertTrue(compareTo(exemplar, greater[i]) == -compareTo(greater[i], exemplar),
+ "Requires compareTo(value, greater[%d]) == -compareTo(greater[%d], value)", i, i);
+ }
+
+ return true;
+}
+
+void
+parcObjectTesting_AssertHashCode(const PARCObject *x, const void *y)
+{
+ assertFalse(x == y, "The parameters x and y cannot be the same value.");
+ assertTrue(parcObject_Equals(x, y), "The parameters x and y must be equal");
+
+ PARCHashCode xCode = parcObject_HashCode(x);
+ PARCHashCode yCode = parcObject_HashCode(y);
+
+ assertTrue(xCode == yCode, "Expected the HashCode of two equal objects to be equal.");
+}
+
+void
+parcObjectTesting_AssertHashCodeImpl(PARCHashCode (*hashCode)(const void *a), void *a)
+{
+ PARCHashCode code1 = hashCode(a);
+ PARCHashCode code2 = hashCode(a);
+ assertTrue(code1 == code2, "HashCode function does not consistently return the same value.");
+}
+
+static void
+_parcObjectTesting_AssertCopy(const PARCObject *instance)
+{
+ PARCObject *copy = parcObject_Copy(instance);
+ if (copy == instance) {
+ parcObject_Release(&copy);
+ assertFalse(true, "Copy should not be the same object");
+ }
+ if (!parcObject_Equals(instance, copy)) {
+ parcObject_Release(&copy);
+ assertTrue(false, "Object fails Copy Test");
+ }
+
+ parcObject_Release(&copy);
+}
+
+static void
+_parcObjectTesting_AssertEqualsWrapper(const PARCObject *a,
+ const PARCObject *b,
+ const PARCObject *c,
+ ...)
+{
+ va_list ap;
+ va_start(ap, c);
+
+ _parcObjectTesting_AssertEquals((bool (*)(const void *, const void *))parcObject_Equals, a, b, c, ap);
+
+ va_end(ap);
+}
+
+static void
+_parcObjectTesting_AssertToJSON(const PARCObject *instance)
+{
+ PARCJSON *json = parcObject_ToJSON(instance);
+ char *result = parcJSON_ToString(json);
+ assertNotNull(result, "Something should be returned");
+ parcMemory_Deallocate(&result);
+ parcJSON_Release(&json);
+}
+
+static void
+_parcObjectTesting_AssertToString(const PARCObject *instance)
+{
+ char *result = parcObject_ToString(instance);
+ assertNotNull(result, "Something should be returned");
+ parcMemory_Deallocate(&result);
+}
+
+void
+parcObjectTesting_AssertObjectConformance(const PARCObject *inst1,
+ const PARCObject *inst2,
+ const PARCObject *inst3,
+ const PARCObject *lesser,
+ const PARCObject *greater)
+{
+ assertNotNull(inst1, "The value of x cannot be NULL.");
+ assertNotNull(inst2, "The value of y cannot be NULL.");
+ assertNotNull(inst3, "The value of z cannot be NULL.");
+ assertNotNull(lesser, "The value of z cannot be NULL.");
+ assertNotNull(greater, "The value of z cannot be NULL.");
+
+ parcObject_AssertValid(inst1);
+ parcObject_AssertValid(inst2);
+ parcObject_AssertValid(inst3);
+ parcObject_AssertValid(lesser);
+ parcObject_AssertValid(greater);
+
+ // Acquire/Release
+ parcObjectTesting_AssertAcquireReleaseImpl(inst1);
+
+ // Equals
+ _parcObjectTesting_AssertEqualsWrapper(inst1, inst2, inst3, lesser, greater, NULL);
+
+ // Copy
+ _parcObjectTesting_AssertCopy(inst1);
+
+ // Compare
+ const void *equals[] = { inst1, inst2, NULL };
+ const void *lessThan[] = { lesser, NULL };
+ const void *greaterThan[] = { greater, NULL };
+ parcObjectTesting_AssertCompareToImpl(parcObject_Compare, inst1, equals, lessThan, greaterThan);
+
+ // HashCode
+ parcObjectTesting_AssertHashCode(inst1, inst2);
+
+ // ToJSON
+ _parcObjectTesting_AssertToJSON(inst1);
+
+ // ToString
+ _parcObjectTesting_AssertToString(inst1);
+}
diff --git a/libparc/parc/testing/parc_ObjectTesting.h b/libparc/parc/testing/parc_ObjectTesting.h
new file mode 100644
index 00000000..557fee10
--- /dev/null
+++ b/libparc/parc/testing/parc_ObjectTesting.h
@@ -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.
+ */
+
+/**
+ * @file parc_ObjectTesting.h
+ * @brief Support for LongBow runtime and unit testing of PARCObject implementations.
+ *
+ */
+#ifndef PARC_Library_parc_ObjectTest_h
+#define PARC_Library_parc_ObjectTest_h
+
+#include <stdarg.h>
+#include <stdbool.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_HashCode.h>
+
+/**
+ * Test if a PARCObject subclass behaves well as a PARCObject when passed to the various PARCObject functions.
+ *
+ * @param [in] inst1 A pointer to an instance that will be used as the base comparison for remaining parameters.
+ * @param [in] inst2 A pointer to an instance that is known to be equal to @p inst1, but is not @p inst1.
+ * @param [in] inst3 A pointer to an instance that is known to be equal to @p inst1 & @p inst2, but is not @p inst1 or @p inst2.
+ * @param [in] lesser A pointer to and instance that are known to be lesser than @p inst1.
+ * @param [in] greater A pointer to and instance that are known to be greater than @p inst1.
+ *
+ * @see parcObjectTesting_AssertEqualsFunction
+ * @see parcObjectTesting_AssertCompareTo
+ * @see parcObjectTesting_AssertAcquire
+ * @see parcObjectTesting_AssertHashCode
+ */
+
+void parcObjectTesting_AssertObjectConformance(const PARCObject *inst1,
+ const PARCObject *inst2,
+ const PARCObject *inst3,
+ const PARCObject *lesser,
+ const PARCObject *greater);
+
+/**
+ * Ensure that a function implements the Equals contract.
+ *
+ * The equality function must implement the following equivalence relations on non-null instances:
+ *
+ * * It is reflexive: for any non-null reference value x, equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, equals(x, y) must return true if and only if
+ * equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * equals(x, y) returns true and
+ * equals(y, z) returns true,
+ * then equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, equals(x, NULL)) must return false.
+ *
+ * @param [in] _function_ A pointer to a function that will be called to determine if it conforms to the Equals contract.
+ * @param [in] _x_ A pointer to a value that will be used as the base comparison for remaining parameters.
+ * @param [in] _y_ A pointer to a value that is known to be equal to @p x, but is not @p x.
+ * @param [in] _z_ A pointer to a value that is known to be equal to @p x and to @p y, but is neither @p x nor @p y.
+ * @param [in] ... A list of pointers to values that are known to be not equal to @p x, @p y, or @p z.
+ * @see parcObjectTesting_AssertEqualsImpl
+ */
+#define parcObjectTesting_AssertEqualsFunction(_function_, _x_, _y_, _z_, ...) \
+ parcObjectTesting_AssertEqualsFunctionImpl((bool (*)(const void *, const void *))_function_, _x_, _y_, _z_, __VA_ARGS__, NULL)
+
+/**
+ * Compares instance a known set of other instances for order.
+ *
+ * The comparison function that this evaluates <i>sgn(a - b)</i> required to return a negative integer,
+ * zero, or a positive integer as <code>a</code> is less than,
+ * equal to, or greater than <code>b</code>.
+ *
+ * The function must ensure that:
+ * <ul>
+ * <li>sgn(compareTo(a, b)) == -sgn(b, a) for all values of a and b.</li>
+ * <li>the relation is transitive: (compareTo(x, y)>0 && compareTo(y, z)>0) implies compareTo(x, z)>0.</li>
+ * <li>compareTo(x, y)== 0 implies that sgn(compareTo(x, z)) == sgn(compareTo(y, z)), for all values of z.</li>
+ * </ul>
+ *
+ * This also stipulates that
+ * <code>compareTo(NULL, NULL)) == 0</code>,
+ * <code>compareTo(not-NULL, NULL)) > 0</code>,
+ * <code>compareTo(NULL, not-NULL)) < 0</code>.
+ *
+ * It is strongly recommended, but not strictly required that relation(compareTo(x, y)==0) == equals(x, y)) is true.
+ * Any module that implements the compareTo function and violates this condition
+ * should clearly indicate this fact.
+ * For example, "Note: this implementation has a natural ordering that is inconsistent with equals."
+ *
+ * @param [in] compareTo A pointer to a function implementing the CompareTo function signature.
+ * @param [in] exemplar The pivotal value under test.
+ * @param [in] equivalent A NULL terminated array of values that are all equivalent to <code>value</code>.
+ * @param [in] lesser A NULL terminated array of values that are all less than <code>value</code>.
+ * @param [in] greater A NULL terminated array of values that are all greater than <code>value</code>.
+ * @see parcObjectTesting_AssertCompareTo
+ */
+#define parcObjectTesting_AssertCompareTo(function, value, equality, lesser, greater) \
+ parcObjectTesting_AssertCompareToImpl((int (*)(const void *, const void *))function, (void *) value, (void *) equality, (void *) lesser, (void *) greater)
+
+#define parcObjectTesting_AssertAcquireReleaseContract(_function_, _instance_) \
+ parcObjectTesting_AssertAcquireReleaseContractImpl((void *(*)(const PARCObject *))_function_, _instance_)
+/**
+ * Assert the acquire/release contract given the Acquire function of a PARCObject implementation.
+ *
+ * Paragraphs Of Explanation
+ *
+ * @param [in] acquireFunction A pointer to the acquireFunction to invoke.
+ * @param [in] instance A pointer to a PARCObject implementation that will be used to acquire and release references.
+ */
+void parcObjectTesting_AssertAcquireReleaseContractImpl(void *(acquireFunction)(const PARCObject *),
+ const PARCObject *instance);
+
+
+#define parcObjectTesting_AssertAcquire(_instance_) \
+ parcObjectTesting_AssertAcquireReleaseImpl((const PARCObject *) _instance_)
+
+/**
+ * Assert that the given PARCObject's Acquire/Release contract is correct.
+ *
+ * @param [in] instance A pointer to a PARCObject instance.
+ */
+void parcObjectTesting_AssertAcquireReleaseImpl(const PARCObject *instance);
+
+/**
+ * Ensure that a function implements the Equals contract.
+ *
+ * The equality function must implement the following equivalence relations on non-null instances:
+ *
+ * * It is reflexive: for any non-null reference value x, equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, equals(x, y) must return true if and only if
+ * equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * equals(x, y) returns true and
+ * equals(y, z) returns true,
+ * then equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, equals(x, NULL)) must return false.
+ *
+ * @param [in] equalsFunction A pointer to a function that will be called to determine if it conforms to the Equals contract.
+ * @param [in] x A pointer to a value that will be used as the base comparison for remaining parameters.
+ * @param [in] y A pointer to a value that is known to be equal to @p x, but is not @p x.
+ * @param [in] z A pointer to a value that is known to be equal to @p x and to @p y, but is neither @p x nor @p y.
+ * @param [in] ... A NULL terminated variable number of parameters consisting of pointers to values that are known to be not equal to @p x, @p y, or @p z.
+ * @see parcObjectTesting_AssertEquals
+ */
+void parcObjectTesting_AssertEqualsFunctionImpl(bool (*equalsFunction)(const void *a, const void *b), const void *x, const void *y, const void *z, ...);
+
+/**
+ * Ensure that a PARCObject implements the Equals contract.
+ *
+ * The PARCObject's `Equals()` function must implement the following equivalence relations on non-null instances:
+ *
+ * * It is reflexive: for any non-null reference value x, equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, equals(x, y) must return true if and only if
+ * equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * equals(x, y) returns true and
+ * equals(y, z) returns true,
+ * then equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, equals(x, NULL)) must return false.
+ *
+ * @param [in] object A pointer to a valid PARCObject instance.
+ * @param [in] y A pointer to a value that is known to be equal to @p object, but is not the same as @p object.
+ * @param [in] z A pointer to a value that is known to be equal to @p object and to @p y, but is neither the same as @p object nor @p y.
+ * @param [in] ... A NULL terminated variable number of parameters consisting of pointers to values that are known to be not equal to @p object, @p y, or @p z.
+ */
+void parcObjectTesting_AssertEquals(const PARCObject *object, const void *y, const void *z, ...);
+
+/**
+ * Compares instance <code>a</code> with instance <code>b</code> for order.
+ *
+ * The comparison function that this evaluates <i>sgn(a - b)</i> required to return a negative integer,
+ * zero, or a positive integer as <code>a</code> is less than,
+ * equal to, or greater than <code>b</code>.
+ *
+ * The function must ensure that:
+ * <ul>
+ * <li>sgn(compareTo(a, b)) == -sgn(b, a) for all values of a and b.</li>
+ * <li>the relation is transitive: (compareTo(x, y)>0 && compareTo(y, z)>0) implies compareTo(x, z)>0.</li>
+ * <li>compareTo(x, y)== 0 implies that sgn(compareTo(x, z)) == sgn(compareTo(y, z)), for all values of z.</li>
+ * </ul>
+ *
+ * This also stipulates that
+ * <code>compareTo(NULL, NULL)) == 0</code>,
+ * <code>compareTo(not-NULL, NULL)) > 0</code>,
+ * <code>compareTo(NULL, not-NULL)) < 0</code>.
+ *
+ * It is strongly recommended, but not strictly required that relation(compareTo(x, y)==0) == equals(x, y)) is true.
+ * Any module that implements the compareTo function and violates this condition
+ * should clearly indicate this fact.
+ * For example, "Note: this implementation has a natural ordering that is inconsistent with equals."
+ *
+ * @param [in] compareTo A pointer to a function implementing the CompareTo function signature.
+ * @param [in] exemplar The pivotal value under test.
+ * @param [in] equivalent A NULL terminated array of values that are all equivalent to <code>value</code>.
+ * @param [in] lesser A NULL terminated array of values that are all less than <code>value</code>.
+ * @param [in] greater A NULL terminated array of values that are all greater than <code>value</code>.
+ * @see parcObjectTesting_AssertCompareTo
+ */
+bool parcObjectTesting_AssertCompareToImpl(int (*compareTo)(const void *a, const void *b),
+ const void *exemplar,
+ const void **equivalent,
+ const void **lesser,
+ const void **greater);
+
+/**
+ * Assert the HashCode contract on a PARCObject.
+ *
+ * @param [in] x A pointer to a valid PARCObject.
+ * @param [in] y A pointer to a valid PARCObject, that must be equal to @p x, but not the same.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+void parcObjectTesting_AssertHashCode(const PARCObject *x, const void *y);
+
+/**
+ * Assert the HashCode function contract.
+ *
+ * @param [in] hashCode A pointer to a function implementing the hash code function.
+ */
+void parcObjectTesting_AssertHashCodeImpl(PARCHashCode (*hashCode)(const void *a), void *a);
+#endif
diff --git a/libparc/parc/testing/test/.gitignore b/libparc/parc/testing/test/.gitignore
new file mode 100644
index 00000000..3b3dc64d
--- /dev/null
+++ b/libparc/parc/testing/test/.gitignore
@@ -0,0 +1,2 @@
+test_parc_MemoryTesting
+test_parc_ObjectTesting
diff --git a/libparc/parc/testing/test/CMakeLists.txt b/libparc/parc/testing/test/CMakeLists.txt
new file mode 100644
index 00000000..1de2e89d
--- /dev/null
+++ b/libparc/parc/testing/test/CMakeLists.txt
@@ -0,0 +1,12 @@
+set(TestsExpectedToPass
+ test_parc_MemoryTesting
+ test_parc_ObjectTesting
+ )
+
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
diff --git a/libparc/parc/testing/test/test_parc_MemoryTesting.c b/libparc/parc/testing/test/test_parc_MemoryTesting.c
new file mode 100755
index 00000000..d24e79d4
--- /dev/null
+++ b/libparc/parc/testing/test/test_parc_MemoryTesting.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../parc_MemoryTesting.c"
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <parc/algol/parc_Memory.h>
+
+LONGBOW_TEST_RUNNER(test_parc_MemoryTest)
+{
+ // 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_parc_MemoryTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_MemoryTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcMemoryTesting_ExpectedOutstanding);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcMemoryTesting_ExpectedOutstanding)
+{
+ void *memory = parcMemory_Allocate(4);
+
+ assertTrue(parcMemoryTesting_ExpectedOutstanding(1, "Expected 1 outstanding allocation"),
+ "Failed 1 expected allocation");
+
+ parcMemory_Deallocate(&memory);
+ assertTrue(parcMemoryTesting_ExpectedOutstanding(0, "Expected 0 outstanding allocations"),
+ "Failed 0 expected allocations");
+
+ assertFalse(parcMemoryTesting_ExpectedOutstanding(1, "Expected 1 outstanding allocations"),
+ "Failed 1 expected llocations");
+ assertFalse(parcMemoryTesting_ExpectedOutstanding(-1, "Expected -1 outstanding allocations"),
+ "Failed -1 expected allocations");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_MemoryTest);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/testing/test/test_parc_ObjectTesting.c b/libparc/parc/testing/test/test_parc_ObjectTesting.c
new file mode 100755
index 00000000..9d70b68c
--- /dev/null
+++ b/libparc/parc/testing/test/test_parc_ObjectTesting.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.
+ */
+
+/**
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_ObjectTesting.c"
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+#include <parc/testing/parc_MemoryTesting.h>
+
+LONGBOW_TEST_RUNNER(test_parc_ObjectTesting)
+{
+ // 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(Static);
+ LONGBOW_RUN_TEST_FIXTURE(CompareTo);
+ LONGBOW_RUN_TEST_FIXTURE(Equals);
+ LONGBOW_RUN_TEST_FIXTURE(AcquireRelease);
+ LONGBOW_RUN_TEST_FIXTURE(Conformance);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_parc_ObjectTesting)
+{
+ 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_parc_ObjectTesting)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestRunner_GetName(testRunner), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static bool
+_equalsFunction(const void *x, const void *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ return (strcmp(x, y) == 0);
+}
+
+static bool
+_equalsFunction_NotReflexive(const void *x, const void *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+ if (x < y) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+LONGBOW_TEST_FIXTURE(Equals)
+{
+ LONGBOW_RUN_TEST_CASE(Equals, parcObjectTesting_AssertEquals);
+
+ LONGBOW_RUN_TEST_CASE(Equals, parcObjectTesting_AssertEqualsFunctionImpl);
+ LONGBOW_RUN_TEST_CASE(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailXYsame);
+ LONGBOW_RUN_TEST_CASE(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailXZsame);
+ LONGBOW_RUN_TEST_CASE(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailXnotequalZ);
+ LONGBOW_RUN_TEST_CASE(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailXnotequalY);
+ LONGBOW_RUN_TEST_CASE(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailNotSymmetric);
+}
+
+static uint32_t _longBowGlobal_Global_outstanding;
+
+LONGBOW_TEST_FIXTURE_SETUP(Equals)
+{
+ _longBowGlobal_Global_outstanding = parcMemory_Outstanding();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Equals)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ if (parcMemoryTesting_ExpectedOutstanding(_longBowGlobal_Global_outstanding, longBowTestCase_GetName(testCase)) == false) {
+ parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ result = LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return result;
+}
+
+LONGBOW_TEST_CASE(Equals, parcObjectTesting_AssertEquals)
+{
+ PARCBuffer *x = parcBuffer_Allocate(sizeof(uint64_t));
+ PARCBuffer *y = parcBuffer_Allocate(sizeof(uint64_t));
+ PARCBuffer *z = parcBuffer_Allocate(sizeof(uint64_t));
+ PARCBuffer *u1 = parcBuffer_Allocate(sizeof(uint64_t));
+ PARCBuffer *u2 = parcBuffer_Allocate(sizeof(uint64_t));
+ parcBuffer_Flip(parcBuffer_PutUint64(x, 1));
+ parcBuffer_Flip(parcBuffer_PutUint64(y, 1));
+ parcBuffer_Flip(parcBuffer_PutUint64(z, 1));
+ parcBuffer_Flip(parcBuffer_PutUint64(u1, 2));
+ parcBuffer_Flip(parcBuffer_PutUint64(u2, 3));
+
+ parcObjectTesting_AssertEquals(x, y, z, u1, u2, NULL);
+ parcBuffer_Release(&x);
+ parcBuffer_Release(&y);
+ parcBuffer_Release(&z);
+ parcBuffer_Release(&u1);
+ parcBuffer_Release(&u2);
+}
+
+LONGBOW_TEST_CASE(Equals, parcObjectTesting_AssertEqualsFunctionImpl)
+{
+ void *x = strdup("1");
+ void *y = strdup("1");
+ void *z = strdup("1");
+ void *u1 = "a";
+ void *u2 = "b";
+
+ parcObjectTesting_AssertEqualsFunctionImpl(_equalsFunction, x, y, z, u1, u2, NULL);
+ free(x);
+ free(y);
+ free(z);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailXYsame, .event = &LongBowAssertEvent)
+{
+ void *x = strdup("1");
+ void *y = x;
+ void *z = strdup("1");
+ void *u1 = "a";
+ void *u2 = "b";
+
+ parcObjectTesting_AssertEqualsFunctionImpl(_equalsFunction, x, y, z, u1, u2, NULL);
+ free(x);
+ free(y);
+ free(z);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailXZsame, .event = &LongBowAssertEvent)
+{
+ void *x = strdup("1");
+ void *y = strdup("1");
+ void *z = x;
+ void *u1 = "a";
+ void *u2 = "b";
+
+ parcObjectTesting_AssertEqualsFunctionImpl(_equalsFunction, x, y, z, u1, u2, NULL);
+ free(x);
+ free(y);
+ free(z);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailXnotequalY, .event = &LongBowAssertEvent)
+{
+ void *x = strdup("1");
+ void *y = strdup("xyzzy");
+ void *z = strdup("1");
+ void *u1 = "a";
+ void *u2 = "b";
+
+ parcObjectTesting_AssertEqualsFunctionImpl(_equalsFunction, x, y, z, u1, u2, NULL);
+ free(x);
+ free(y);
+ free(z);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailXnotequalZ, .event = &LongBowAssertEvent)
+{
+ void *x = strdup("1");
+ void *y = strdup("1");
+ void *z = strdup("xyzzy");
+ void *u1 = "a";
+ void *u2 = "b";
+
+ parcObjectTesting_AssertEqualsFunctionImpl(_equalsFunction, x, y, z, u1, u2, NULL);
+ free(x);
+ free(y);
+ free(z);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Equals, parcObjectTesting_AssertEqualsFunctionImpl_FailNotSymmetric, .event = &LongBowAssertEvent)
+{
+ void *x = strdup("1");
+ void *y = strdup("1");
+ void *z = strdup("1");
+ void *u1 = "a";
+ void *u2 = "b";
+
+ parcObjectTesting_AssertEqualsFunctionImpl(_equalsFunction_NotReflexive, x, y, z, u1, u2, NULL);
+ free(x);
+ free(y);
+ free(z);
+}
+
+LONGBOW_TEST_FIXTURE(AcquireRelease)
+{
+ LONGBOW_RUN_TEST_CASE(AcquireRelease, parcObjectTesting_AssertAcquire);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(AcquireRelease)
+{
+ _longBowGlobal_Global_outstanding = parcMemory_Outstanding();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(AcquireRelease)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ if (parcMemoryTesting_ExpectedOutstanding(_longBowGlobal_Global_outstanding, longBowTestCase_GetName(testCase)) == false) {
+ parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ result = LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return result;
+}
+
+LONGBOW_TEST_CASE(AcquireRelease, parcObjectTesting_AssertAcquire)
+{
+ PARCBuffer *buffer = parcBuffer_Allocate(10);
+ parcObjectTesting_AssertAcquireReleaseImpl(buffer);
+ parcBuffer_Release(&buffer);
+}
+
+
+LONGBOW_TEST_FIXTURE(CompareTo)
+{
+ LONGBOW_RUN_TEST_CASE(CompareTo, parcObjectTesting_AssertCompareTo);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CompareTo)
+{
+ _longBowGlobal_Global_outstanding = parcMemory_Outstanding();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CompareTo)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ if (parcMemoryTesting_ExpectedOutstanding(_longBowGlobal_Global_outstanding, longBowTestCase_GetName(testCase)) == false) {
+ parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ result = LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return result;
+}
+
+LONGBOW_TEST_CASE(CompareTo, parcObjectTesting_AssertCompareTo)
+{
+ PARCBuffer *x = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+ PARCBuffer *y = parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10, 0, 10);
+
+ PARCBuffer *equivalent[] = {
+ x,
+ y,
+ NULL
+ };
+ PARCBuffer *lesser[] = {
+ parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8 }, 10, 0, 10),
+ parcBuffer_Wrap((uint8_t [9]) { 0, 1, 2, 3, 4, 5, 5, 7, 8, }, 9, 0, 9),
+ NULL
+ };
+ PARCBuffer *greater[] = {
+ parcBuffer_Wrap((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }, 10, 0, 10),
+ parcBuffer_Wrap((uint8_t [11]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 11, 0, 11),
+ NULL
+ };
+
+ parcObjectTesting_AssertCompareTo(parcBuffer_Compare, x, equivalent, lesser, greater);
+
+ parcBuffer_Release(&x);
+ parcBuffer_Release(&y);
+
+ for (int i = 0; lesser[i] != NULL; i++) {
+ parcBuffer_Release(&lesser[i]);
+ }
+ for (int i = 0; greater[i] != NULL; i++) {
+ parcBuffer_Release(&greater[i]);
+ }
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ _longBowGlobal_Global_outstanding = parcMemory_Outstanding();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ size_t allocationsLeaked = parcMemory_Outstanding() - _longBowGlobal_Global_outstanding;
+
+ if (allocationsLeaked) {
+ printf("%s leaks memory by %zd allocations\n", longBowTestCase_GetName(testCase), allocationsLeaked);
+ parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ result = LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return result;
+}
+
+LONGBOW_TEST_FIXTURE(Conformance)
+{
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_succeed);
+
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_fail_non_object);
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_equals);
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_compare);
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_copy_junk);
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_copy_same);
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_hash);
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_toString);
+ LONGBOW_RUN_TEST_CASE(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_toJSON);
+}
+
+
+typedef struct {
+ PARCBuffer *inst1;
+ PARCBuffer *inst2;
+ PARCBuffer *inst3;
+ PARCBuffer *lesser;
+ PARCBuffer *greater;
+ PARCObjectDescriptor *descriptor;
+} TestData_t;
+
+static const PARCObjectDescriptor *
+_copyDescriptor(const PARCObjectDescriptor *orig)
+{
+ return parcObjectDescriptor_Create("Name",
+ orig->objectSize,
+ orig->objectAlignment,
+ orig->isLockable,
+ orig->destructor,
+ orig->release, orig->copy,
+ orig->toString, orig->equals,
+ orig->compare, orig->hashCode,
+ orig->toJSON, orig->display,
+ orig->super, orig->typeState);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Conformance)
+{
+ TestData_t *data = parcMemory_AllocateAndClear(sizeof(TestData_t));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData_t));
+
+ data->inst1 = parcBuffer_Flip(parcBuffer_CreateFromArray((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10));
+ data->inst2 = parcBuffer_Flip(parcBuffer_CreateFromArray((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10));
+ data->inst3 = parcBuffer_Flip(parcBuffer_CreateFromArray((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 10));
+ data->lesser = parcBuffer_Flip(parcBuffer_CreateFromArray((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8 }, 10));
+ data->greater = parcBuffer_Flip(parcBuffer_CreateFromArray((uint8_t [10]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10 }, 10));
+
+ PARCObjectDescriptor *d = (PARCObjectDescriptor *) parcObject_GetDescriptor(data->inst1);
+ data->descriptor = (PARCObjectDescriptor *) _copyDescriptor(d);
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Conformance)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcBuffer_Release(&data->inst1);
+ parcBuffer_Release(&data->inst2);
+ parcBuffer_Release(&data->inst3);
+ parcBuffer_Release(&data->lesser);
+ parcBuffer_Release(&data->greater);
+
+ parcObjectDescriptor_Destroy(&data->descriptor);
+
+ parcMemory_Deallocate(&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(Conformance, parcObjectTesting_AssertObjectConformance_succeed)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcObjectTesting_AssertObjectConformance(data->inst1, data->inst2, data->inst3, data->lesser, data->greater);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Conformance, parcObjectTesting_AssertObjectConformance_fail_non_object, .event = &LongBowAssertEvent)
+{
+ char *inst1 = "not an object";
+ char *inst2 = "not an object";
+ char *inst3 = "not an object";
+
+ parcObjectTesting_AssertObjectConformance(inst1, inst2, inst3, NULL, NULL);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_equals, .event = &LongBowAssertEvent)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+ PARCBuffer *inst1 = data->inst1;
+ PARCBuffer *inst2 = inst1;
+ PARCBuffer *inst3 = inst1;
+
+ parcObjectTesting_AssertObjectConformance(inst1, inst2, inst3, data->lesser, data->greater);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_compare, .event = &LongBowAssertEvent)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+
+ parcObjectTesting_AssertObjectConformance(data->inst1, data->inst2, data->inst3, data->greater, data->lesser);
+}
+
+__attribute__ ((noinline))
+static PARCObject *
+badCopyJunk(const PARCObject *instance)
+{
+ return parcBuffer_Allocate(10);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_copy_junk, .event = &LongBowAssertEvent)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+
+ data->descriptor->copy = badCopyJunk;
+ parcObject_SetDescriptor(data->inst1, data->descriptor);
+
+ parcObjectTesting_AssertObjectConformance(data->inst1, data->inst2, data->inst3, data->greater, data->lesser);
+}
+
+static PARCObject *
+badCopySame(const PARCObject *instance)
+{
+ return parcObject_Acquire(instance);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_copy_same, .event = &LongBowAssertEvent)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+
+ data->descriptor->copy = badCopySame;
+ parcObject_SetDescriptor(data->inst1, data->descriptor);
+
+ parcObjectTesting_AssertObjectConformance(data->inst1, data->inst2, data->inst3, data->greater, data->lesser);
+}
+
+static PARCHashCode
+badHash(const PARCObject *instance)
+{
+ return (PARCHashCode) instance;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_hash, .event = &LongBowAssertEvent)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+
+ data->descriptor->hashCode = badHash;
+ parcObject_SetDescriptor(data->inst1, data->descriptor);
+
+ parcObjectTesting_AssertObjectConformance(data->inst1, data->inst2, data->inst3, data->greater, data->lesser);
+}
+
+static PARCJSON *
+badToJSON(const PARCObject *instance)
+{
+ return NULL;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_toJSON, .event = &LongBowAssertEvent)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+
+ data->descriptor->toJSON = badToJSON;
+ parcObject_SetDescriptor(data->inst1, data->descriptor);
+
+ parcObjectTesting_AssertObjectConformance(data->inst1, data->inst2, data->inst3, data->greater, data->lesser);
+}
+
+static char *
+badToString(const PARCObject *instance)
+{
+ return NULL;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Conformance, parcObjectTesting_AssertObjectConformance_fail_object_toString, .event = &LongBowAssertEvent)
+{
+ TestData_t *data = longBowTestCase_GetClipBoardData(testCase);
+
+ data->descriptor->toString = badToString;
+ parcObject_SetDescriptor(data->inst1, data->descriptor);
+
+ parcObjectTesting_AssertObjectConformance(data->inst1, data->inst2, data->inst3, data->greater, data->lesser);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_ObjectTesting);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/scripts/build-package.sh b/libparc/scripts/build-package.sh
new file mode 100644
index 00000000..102d05d1
--- /dev/null
+++ b/libparc/scripts/build-package.sh
@@ -0,0 +1,198 @@
+#!/bin/bash
+# basic build script example
+set -euxo pipefail
+IFS=$'\n\t'
+
+SCRIPT_PATH=$( cd "$(dirname "${BASH_SOURCE}")" ; pwd -P )
+APT_PATH=`which apt-get` || true
+apt_get=${APT_PATH:-"/usr/local/bin/apt-get"}
+
+BUILD_TOOLS_UBUNTU="build-essential doxygen"
+LIBSSL_LIBEVENT_UBUNTU="libevent-dev libssl-dev"
+DEPS_UBUNTU="longbow-dev $LIBSSL_LIBEVENT_UBUNTU"
+
+BUILD_TOOLS_GROUP_CENTOS="'Development Tools'"
+LIBSSL_LIBEVENT_CENTOS="libevent-devel openssl-devel"
+DEPS_CENTOS="longbow-devel $LIBSSL_LIBEVENT_CENTOS"
+
+update_cmake_repo() {
+
+ cat /etc/resolv.conf
+ echo "nameserver 8.8.8.8" | sudo tee -a /etc/resolv.conf
+ cat /etc/resolv.conf
+
+ CMAKE_INSTALL_SCRIPT_URL="https://cmake.org/files/v3.8/cmake-3.8.0-Linux-x86_64.sh"
+ CMAKE_INSTALL_SCRIPT="/tmp/install_cmake.sh"
+ curl ${CMAKE_INSTALL_SCRIPT_URL} > ${CMAKE_INSTALL_SCRIPT}
+
+ sudo mkdir -p /opt/cmake
+ sudo bash ${CMAKE_INSTALL_SCRIPT} --skip-license --prefix=/opt/cmake
+ export PATH=/opt/cmake/bin:$PATH
+}
+
+# Parameters:
+# $1 = Distribution codename
+#
+update_qt_repo() {
+ DISTRIBUTION_CODENAME=$1
+
+ if [ "$DISTRIBUTION_CODENAME" != "trusty" ] && [ "$DISTRIBUTION_CODENAME" != "xenial" ]; then
+ echo "No valid distribution specified when calling 'update_qt_repo'. Exiting.."
+ exit -1
+ fi
+
+ sudo ${apt_get} install -y --allow-unauthenticated software-properties-common
+ sudo add-apt-repository --yes ppa:beineri/opt-qt571-$DISTRIBUTION_CODENAME
+
+ wget -q -O - http://archive.getdeb.net/getdeb-archive.key | sudo apt-key add -
+ sudo sh -c "echo 'deb http://archive.getdeb.net/ubuntu $DISTRIBUTION_CODENAME-getdeb apps' >> /etc/apt/sources.list.d/getdeb.list"
+
+ sudo ${apt_get} update
+}
+
+# Parameters:
+# $1 = Distribution id
+# $2 = Distribution codename
+#
+update_fdio_repo() {
+ DISTRIB_ID=$1
+ DISTRIB_CODENAME=$2
+
+ NEXUS_PROXY=${NEXUSPROXY:-"http://nexus.fd.io"}
+ REPO_CICN_URL=""
+ REPO_VPP_URL=""
+
+ if [ "$DISTRIB_ID" == "Ubuntu" ]; then
+
+ if [ "$DISTRIB_CODENAME" == "xenial" ]; then
+ REPO_VPP_URL="${NEXUS_PROXY}/content/repositories/fd.io.stable.1701.ubuntu.xenial.main/"
+ REPO=${REPO_NAME:-"master.ubuntu.xenial.main"}
+ REPO_CICN_URL="${NEXUS_PROXY}/content/repositories/fd.io.${REPO}"
+ elif [ "$DISTRIB_CODENAME" == "trusty" ]; then
+ REPO_VPP_URL="${NEXUS_PROXY}/content/repositories/fd.io.stable.1701.ubuntu.trusty.main/"
+ REPO=${REPO_NAME:-"master.ubuntu.trusty.main"}
+ REPO_CICN_URL="${NEXUS_PROXY}/content/repositories/fd.io.${REPO}"
+ else
+ echo "Distribution $DISTRIB_CODENAME is not supported"
+ exit -1
+ fi
+
+ echo "deb ${REPO_VPP_URL} ./" | sudo tee /etc/apt/sources.list.d/99fd.io.list
+ echo "deb ${REPO_CICN_URL} ./" | sudo tee /etc/apt/sources.list.d/99fd.io.master.list
+
+ elif [ "$DISTRIB_ID" == "CentOS" ]; then
+ REPO_VPP_URL="${NEXUS_PROXY}/content/repositories/fd.io.centos7/"
+ REPO=${REPO_NAME:-"master.centos7"}
+ REPO_CICN_URL="${NEXUS_PROXY}/content/repositories/fd.io.${REPO}"
+
+ sudo cat << EOF > fdio.repo
+[fdio-vpp-master]
+name=fd.io master branch latest merge
+baseurl=${REPO_VPP_URL}
+enabled=1
+gpgcheck=0
+
+[fdio-cicn-master]
+name=fd.io master branch latest merge
+baseurl=${REPO_CICN_URL}
+enabled=1
+gpgcheck=0
+EOF
+ sudo mv fdio.repo /etc/yum.repos.d/fdio.repo
+ else
+ echo "Distribution $DISTRIB_CODENAME is not supported"
+ exit -1
+ fi
+}
+
+setup() {
+
+ DISTRIB_ID=$1
+ DISTRIB_CODENAME=$2
+
+ update_cmake_repo
+ update_fdio_repo $DISTRIB_ID $DISTRIB_CODENAME
+
+
+ if [ "$DISTRIB_ID" == "Ubuntu" ]; then
+ sudo ${apt_get} update || true
+ fi
+}
+
+# Parameters:
+# $1 = Package name
+#
+build_package() {
+
+ PACKAGE_NAME=$1
+
+ ARCHITECTURE=`uname -m`
+
+ # Figure out what system we are running on
+ if [ -f /etc/lsb-release ];then
+
+ . /etc/lsb-release
+ DEB=ON
+ RPM=OFF
+
+ if [ "$ARCHITECTURE" == "x86_64" ]; then
+ ARCHITECTURE="amd64"
+ fi
+
+ elif [ -f /etc/redhat-release ];then
+
+ sudo yum install -y redhat-lsb
+ DISTRIB_ID=`lsb_release -si`
+ DISTRIB_RELEASE=`lsb_release -sr`
+ DISTRIB_CODENAME=`lsb_release -sc`
+ DISTRIB_DESCRIPTION=`lsb_release -sd`
+
+ DEB=OFF
+ RPM=ON
+ else
+ echo "ERROR: System configuration not recognized. Build failed"
+ exit -1
+ fi
+
+ echo ARCHITECTURE: $ARCHITECTURE
+ echo DISTRIB_ID: $DISTRIB_ID
+ echo DISTRIB_RELEASE: $DISTRIB_RELEASE
+ echo DISTRIB_CODENAME: $DISTRIB_CODENAME
+ echo DISTRIB_DESCRIPTION: $DISTRIB_DESCRIPTION
+
+ setup $DISTRIB_ID $DISTRIB_CODENAME
+
+ # Install package dependencies
+ if [ $DISTRIB_ID == "Ubuntu" ]; then
+ echo $BUILD_TOOLS_UBUNTU $DEPS_UBUNTU | xargs sudo ${apt_get} install -y --allow-unauthenticated
+ elif [ $DISTRIB_ID == "CentOS" ]; then
+ echo $BUILD_TOOLS_GROUP_CENTOS | xargs sudo yum groupinstall -y --nogpgcheck
+ echo $DEPS_CENTOS | xargs sudo yum install -y --nogpgcheck || true
+ fi
+
+ # do nothing but print the current slave hostname
+ hostname
+
+ # Make the package
+ mkdir -p $SCRIPT_PATH/../build && pushd $SCRIPT_PATH/../build
+
+ rm -rf *
+ cmake -DCMAKE_INSTALL_PREFIX=/usr -DRPM_PACKAGE=$RPM -DDEB_PACKAGE=$DEB -DDISTRIBUTION=$DISTRIB_CODENAME -DARCHITECTURE=$ARCHITECTURE ..
+ make package
+
+ find . -not -name '*.deb' -not -name '*.rpm' -print0 | xargs -0 rm -rf -- || true
+
+ popd
+
+ echo "*******************************************************************"
+ echo "* $PACKAGE_NAME BUILD SUCCESSFULLY COMPLETED"
+ echo "*******************************************************************"
+
+ exit 0
+}
+
+PACKAGE_NAME="LIBPARC"
+PACKAGE_DEPS="LIBPARC_DEPS"
+pushd $SCRIPT_PATH/..
+build_package $PACKAGE_NAME
+popd
diff --git a/libparc/scripts/version b/libparc/scripts/version
new file mode 100644
index 00000000..dcf81d30
--- /dev/null
+++ b/libparc/scripts/version
@@ -0,0 +1,57 @@
+#!/bin/bash
+
+path=$( cd "$(dirname "${BASH_SOURCE}")" ; pwd -P )
+version_prefix="Libparc-v"
+
+cd "$path"
+
+git rev-parse 2> /dev/null
+if [ $? == 0 ]; then
+ vstring=$(git describe --dirty --match "$version_prefix*" | sed "s/$version_prefix//")
+elif [ -f .version ]; then
+ vstring=$(cat .version)
+else
+ if [ -f ../rpm/*.gz ]; then
+ vstring=$(ls ../rpm/*.gz)
+ else
+ exit 1
+ fi
+fi
+
+TAG=$(echo ${vstring} | cut -d- -f1 | sed -e "s/$version_prefix//")
+ADD=$(echo ${vstring} | cut -s -d- -f2)
+
+git rev-parse 2> /dev/null
+if [ $? == 0 ]; then
+ CMT=$(git describe --dirty --match "$version_prefix*" | sed "s/$version_prefix//" | cut -s -d- -f3,4)
+else
+ CMT=$(echo ${vstring} | cut -s -d- -f3,4)
+fi
+CMTR=$(echo $CMT | sed 's/-/_/')
+
+if [ -n "${BUILD_NUMBER}" ]; then
+ BLD="~b${BUILD_NUMBER}"
+else
+ BLD="~b1"
+fi
+
+if [ "$1" = "rpm-version" ]; then
+ echo ${TAG}
+ exit
+fi
+
+if [ "$1" = "rpm-release" ]; then
+ [ -z "${ADD}" ] && echo release && exit
+ echo ${ADD}${CMTR:+~${CMTR}}${BLD}
+ exit
+fi
+
+ if [ -n "${ADD}" ]; then
+ if [ "$1" = "rpm-string" ]; then
+ echo ${TAG}-${ADD}${CMTR:+~${CMTR}}${BLD}
+ else
+ echo ${TAG}-${ADD}${CMT:+~${CMT}}${BLD}
+ fi
+ else
+ echo ${TAG}-release
+fi \ No newline at end of file
diff --git a/longbow/.gitignore b/longbow/.gitignore
new file mode 100644
index 00000000..2a963e9c
--- /dev/null
+++ b/longbow/.gitignore
@@ -0,0 +1,30 @@
+build
+=======
+liblongbow*tar.gz
+lib
+bin
+include
+*.o
+*.lo
+*.a
+*.la
+.libs
+a.out
+.DS_Store
+.gcda
+.gcno
+.dSYM
+autom4te.cache
+config.h
+config.log
+config.status
+stamp-h1
+*.trs
+Makefile
+.deps
+*.pyc
+.dirstamp
+*.swp
+libtool
+*~
+.idea
diff --git a/longbow/AUTHORS b/longbow/AUTHORS
new file mode 100644
index 00000000..0bb46a2f
--- /dev/null
+++ b/longbow/AUTHORS
@@ -0,0 +1,7 @@
+LongBow authors are listed below
+
+ Glenn Scott <Glenn.Scott@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/longbow/BASE_VERSION b/longbow/BASE_VERSION
new file mode 100644
index 00000000..d3827e75
--- /dev/null
+++ b/longbow/BASE_VERSION
@@ -0,0 +1 @@
+1.0
diff --git a/longbow/CMakeLists.txt b/longbow/CMakeLists.txt
new file mode 100644
index 00000000..ee2798a1
--- /dev/null
+++ b/longbow/CMakeLists.txt
@@ -0,0 +1,174 @@
+cmake_minimum_required(VERSION 3.2)
+project(LongBow)
+
+include( CTest )
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
+
+set(CMAKE_C_STANDARD 99)
+set(CMAKE_C_STANDARD_REQUIRED ON)
+
+if (NOT CMAKE_BUILD_TYPE)
+ message(STATUS "No build type selected, default to Release")
+ set(CMAKE_BUILD_TYPE "Release")
+endif ()
+
+set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+
+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}\"")
+
+find_package( Doxygen )
+find_package( Uncrustify )
+find_package( PythonInterp )
+
+set( DEPENDENCY_DIR $ENV{CCNX_DEPENDENCIES} )
+if( NOT DEPENDENCY_DIR )
+ set( DEPENDENCY_DIR /usr )
+endif()
+
+set( PYVERSION ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} )
+
+set( INSTALL_BASE_PYTHON_DIR ${CMAKE_INSTALL_PREFIX}/lib/python${PYVERSION}/site-packages )
+set( INSTALL_PYTHON_DIR ${INSTALL_BASE_PYTHON_DIR}/longbow )
+set( DEPENDENCY_PYTHON_DIR ${DEPENDENCY_DIR}/etc/site-packages )
+set( VERSION ${RELEASE_VERSION} )
+set( DATE ${ISO_DATE} )
+set( UNCRUSTIFY_BIN ${UNCRUSTIFY_BIN} )
+set( UNCRUSTIFY_CONFIG ${CMAKE_INSTALL_PREFIX}/etc/parc_uncrustify.cfg )
+
+message( "-- Install Python Dir: ${INSTALL_PYTHON_DIR}")
+message( "-- Dependency Python Dir: ${DEPENDENCY_DIR}/etc/site-packages")
+include_directories(${PROJECT_BINARY_DIR}/src/LongBow ${PROJECT_SOURCE_DIR}/src)
+
+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")
+
+ macro(AddTest testFile)
+ message("Android build: Skipping test ${ARGV0}")
+ endmacro(AddTest)
+
+ add_subdirectory(src)
+elseif(COMPILE_FOR_IOS)
+ 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} -Wall")
+
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${CMAKE_C_FLAGS}")
+ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${CMAKE_C_FLAGS} -DLongBow_DISABLE_ASSERTIONS")
+ set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${CMAKE_C_FLAGS}")
+ set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${CMAKE_C_FLAGS}")
+
+ macro(AddTest testFile)
+ message("IOS build: Skipping test ${ARGV0}")
+ endmacro(AddTest)
+ add_subdirectory(src)
+else()
+
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE")
+
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${CMAKE_C_FLAGS}")
+ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${CMAKE_C_FLAGS} -DLongBow_DISABLE_ASSERTIONS")
+ set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${CMAKE_C_FLAGS}")
+ set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${CMAKE_C_FLAGS}")
+
+ macro(AddTest testFile)
+ add_executable(${ARGV0} ${ARGV0}.c)
+ target_link_libraries(${ARGV0} ${PARC_BIN_LIBRARIES})
+ add_test(${ARGV0} ${ARGV0})
+ set_target_properties(${ARGV0} PROPERTIES FOLDER Test)
+ endmacro(AddTest)
+
+ add_subdirectory(src)
+ add_subdirectory(documentation)
+endif()
+
+# Generate DEB / RPM packages
+
+option(DEB_PACKAGE "Create deb package" OFF)
+option(RPM_PACKAGE "Create deb package" OFF)
+
+set(VENDOR "Cisco Systems" CACHE STRING "Vendor")
+set(CONTACT "msardara@cisco.com" CACHE STRING "Contact")
+set(DISTRIBUTION "xenial" CACHE STRING "Distribution")
+set(ARCHITECTURE "amd64" CACHE STRING "Architecture")
+set(PACKAGE_MAINTAINER "Mauro Sardara (msardara@cisco.com)" CACHE STRING "Maintainer")
+string(TOLOWER ${CMAKE_PROJECT_NAME} PACKAGE_NAME)
+set(CPACK_PACKAGING_INSTALL_PREFIX "/usr")
+set(CPACK_PACKAGE_VENDOR ${VENDOR})
+set(CPACK_PACKAGE_CONTACT ${CONTACT})
+set(CPACK_COMPONENTS_ALL library headers documentation)
+
+# Get the version
+execute_process(COMMAND bash ${CMAKE_SOURCE_DIR}/scripts/version
+ OUTPUT_VARIABLE PACKAGE_VERSION)
+
+if (PACKAGE_VERSION)
+ string(STRIP ${PACKAGE_VERSION} PACKAGE_VERSION)
+else()
+ set(PACKAGE_VERSION 1.0)
+endif()
+
+if(DEB_PACKAGE)
+ set(TYPE "DEBIAN")
+ set(GENERATOR "DEB")
+
+ set(CPACK_${TYPE}_LIBRARY_PACKAGE_NAME "${PACKAGE_NAME}")
+ set(CPACK_${TYPE}_HEADERS_PACKAGE_NAME "${PACKAGE_NAME}-dev")
+ set(CPACK_${TYPE}_DOCUMENTATION_PACKAGE_NAME "${PACKAGE_NAME}-doc")
+
+ set(CPACK_${TYPE}_LIBRARY_FILE_NAME "${PACKAGE_NAME}_${PACKAGE_VERSION}_${ARCHITECTURE}.deb")
+ set(CPACK_${TYPE}_HEADERS_FILE_NAME "${PACKAGE_NAME}-dev_${PACKAGE_VERSION}_${ARCHITECTURE}.deb")
+ set(CPACK_${TYPE}_DOCUMENTATION_FILE_NAME "${PACKAGE_NAME}-doc_${PACKAGE_VERSION}_${ARCHITECTURE}.deb")
+
+ set(CPACK_DEBIAN_LIBRARY_PACKAGE_SHLIBDEPS ON)
+
+ set(CPACK_${TYPE}_LIBRARY_PACKAGE_DEPENDS "python (>= 2.7.0)")
+ set(CPACK_${TYPE}_HEADERS_PACKAGE_DEPENDS "longbow (>= 1.0)")
+ set(CPACK_${TYPE}_DOCUMENTATION_PACKAGE_DEPENDS "")
+elseif(RPM_PACKAGE)
+ set(TYPE "RPM")
+ set(GENERATOR "RPM")
+
+ set(CPACK_${TYPE}_LIBRARY_PACKAGE_NAME "${PACKAGE_NAME}")
+ set(CPACK_${TYPE}_HEADERS_PACKAGE_NAME "${PACKAGE_NAME}-devel")
+ set(CPACK_${TYPE}_DOCUMENTATION_PACKAGE_NAME "${PACKAGE_NAME}-doc")
+
+ set(CPACK_${TYPE}_LIBRARY_FILE_NAME "${PACKAGE_NAME}-${PACKAGE_VERSION}.${ARCHITECTURE}.rpm")
+ set(CPACK_${TYPE}_HEADERS_FILE_NAME "${PACKAGE_NAME}-devel-${PACKAGE_VERSION}.${ARCHITECTURE}.rpm")
+ set(CPACK_${TYPE}_DOCUMENTATION_FILE_NAME "${PACKAGE_NAME}-doc-${PACKAGE_VERSION}.${ARCHITECTURE}.rpm")
+
+ set(CPACK_${TYPE}_LIBRARY_PACKAGE_AUTOREQ ON)
+
+ set(CPACK_${TYPE}_LIBRARY_PACKAGE_REQUIRES "python >= 2.7.0")
+ set(CPACK_${TYPE}_HEADERS_PACKAGE_REQUIRES "longbow >= 1.0")
+ set(CPACK_${TYPE}_DOCUMENTATION_PACKAGE_REQUIRES "")
+
+ set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/usr/etc" "/usr/lib/python2.7" "/usr/lib/python2.7/site-packages")
+else()
+ return()
+endif()
+
+set(CPACK_GENERATOR ${GENERATOR})
+set(CPACK_${GENERATOR}_COMPONENT_INSTALL ON)
+set(CPACK_${TYPE}_PACKAGE_MAINTAINER ${PACKAGE_MAINTAINER})
+set(CPACK_${TYPE}_PACKAGE_NAME ${PACKAGE_NAME})
+set(CPACK_${TYPE}_PACKAGE_VERSION ${PACKAGE_VERSION})
+set(CPACK_${TYPE}_PACKAGE_ARCHITECTURE ${ARCHITECTURE})
+set(CPACK_${TYPE}_PACKAGE_RELEASE 1)
+set(CPACK_${TYPE}_PACKAGE_VENDOR ${VENDOR})
+set(CPACK_${TYPE}_PACKAGE_DESCRIPTION "Runtime and testing framework for C applications.")
+set(CPACK_${TYPE}_PACKAGE_HOMEPAGE "https://wiki.fd.io/view/Cframework")
+
+include(CPack)
diff --git a/longbow/LICENSE b/longbow/LICENSE
new file mode 100644
index 00000000..318b3f59
--- /dev/null
+++ b/longbow/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/longbow/README.md b/longbow/README.md
new file mode 100644
index 00000000..5da82a69
--- /dev/null
+++ b/longbow/README.md
@@ -0,0 +1,113 @@
+LongBow
+=======
+_The Best Defense is a Good Offense_
+
+The LongBow C language software framework
+
+## Quick Start ##
+
+```
+$ git clone -b cframework/master https://gerrit.fd.io/r/cicn cframework
+$ cd cframework/longbow
+$ mkdir build
+$ cd build
+$ cmake ..
+$ make
+$ make test
+$ make install
+```
+
+## Introduction ##
+
+LongBow is a C language software framework that combines the fail-fast philosophy of an offensive-stance of program
+development and xUnit style unit testing. Using LongBow's to aid an offensive-development stance is largely a matter
+of using its entry and exit assertions in your code. Similarly using LongBow's unit-test framework uses the same entry
+and exit assertions in the unit test cases themselves. The runtime assertions and the unit-test assertions work
+together in the unit test framework and do not conflict. This framework grew out of the need for a unit testing for
+Test Driven Development on the CCNx Distillery software distribution.
+Two other test frameworks were considered and used to develop unit tests: Unity and GoogleTest. Ultimately Unity
+was not used (although this framework is indebted to Unity for inspiration) mainly due to ease-of-use problems,
+and Googletest was not used mainly because it is a C++ framework, is not compatible with some features of C99, and is
+difficult to use.
+
+## Using LongBow ##
+
+### Platforms ###
+
+LongBow has been tested in:
+
+- Ubuntu 16.04 (x86_64)
+- Debian Testing
+- MacOSX 10.12
+
+Other platforms and architectures may work.
+
+### Dependencies ###
+
+- c99 (clang / gcc)
+- CMake 3.4
+- Python 2.7
+
+While the LongBow unit test framework and runtime assertions don't have any unusual requirements other than CMake,
+the software quality development tools that LongBow provides can make use of the following tools:
+
+- Doxygen
+- Uncrustify
+
+### Using LongBow ###
+
+#### LongBow Lib
+
+To use LongBow in your software you will need to link your programs to the LongBow libraries.
+Longbow comes as a set of libraries. A main library and a set of reporting libraries. Your software will need to
+link to the main library (`liblongbow`) and one of the reporting libraries. Currently there are 2 reporting libraries
+available `longbow-textplain` and `longbow-ansiterm`.
+
+```
+LONGBOW_DIR=<directory-where-longbow-is-installed>
+
+-I${LONGBOW_DIR}/include -L${LONGBOW_DIR}/lib -llongbow -llongbow_textplain.a
+```
+
+#### LongBow Unit Testing
+
+LongBow unit testing works in conjuction with the LongBow library. Please take a look at the examples and the
+documentation for information on how to write unit tests. You can also look at some of the software that uses LongBow
+for unit testing as examples. A good starting point would be Libparc.
+
+#### LongBow Utilities
+
+LongBow comes with a set of utilities (scripts) to make C programs better. This includes code analysis and reporting
+tools. You will find these in the `${INSTALL_DIR}/bin` directory. Each of those utilities should come with a `-h`
+option that will give you online help. For more information please check the LongBow documentation.
+
+### GDB and LongBow ###
+LongBow uses signals to interrupt program flow when an assertion fails.
+When using `gdb` this will cause `gdb` to stop running of the test which probably isn't what you want.
+You probably would prefer that gdb just ignore the signal and let the LongBow unit test signal handler take care of the
+signal. To do this, you must configure `gdb` to ignore the signal and to allow it to pass to the programme being
+executed.
+
+`handle 6 nostop pass`
+
+
+### 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/longbow/cmake/Modules/FindUncrustify.cmake b/longbow/cmake/Modules/FindUncrustify.cmake
new file mode 100644
index 00000000..e53f65fe
--- /dev/null
+++ b/longbow/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/longbow/cmake/get_version.sh b/longbow/cmake/get_version.sh
new file mode 100755
index 00000000..34c6ddb2
--- /dev/null
+++ b/longbow/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/longbow/documentation/.gitignore b/longbow/documentation/.gitignore
new file mode 100644
index 00000000..3d3b0c69
--- /dev/null
+++ b/longbow/documentation/.gitignore
@@ -0,0 +1,4 @@
+build
+*.log
+longbow-documentation
+longbow.doctags
diff --git a/longbow/documentation/CMakeLists.txt b/longbow/documentation/CMakeLists.txt
new file mode 100644
index 00000000..61e9f8b6
--- /dev/null
+++ b/longbow/documentation/CMakeLists.txt
@@ -0,0 +1,45 @@
+find_package(Doxygen)
+
+if(DOXYGEN_FOUND)
+ set(PARC_REMOTE http://githubenterprise.parc.com/CCNX/LongBow)
+ set(GITHUB_REMOTE http://github.com/PARC/LongBow)
+ configure_file(longbow.doxygen.in config.doxygen @ONLY)
+
+ install(DIRECTORY images/ DESTINATION ${CMAKE_INSTALL_PREFIX}/share/doc/longbow/images COMPONENT documentation)
+ install(DIRECTORY doxygen-extras/ DESTINATION ${CMAKE_INSTALL_PREFIX}/share/doc/longbow/doxygen-extras COMPONENT documentation)
+ install(DIRECTORY examples/ DESTINATION ${CMAKE_INSTALL_PREFIX}/share/doc/longbow/examples COMPONENT documentation)
+ install(FILES DoxygenLayout.xml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/doc/longbow COMPONENT documentation)
+
+ 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 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
+ DEPENDS ${HTML_PATH}/.git/config
+ WORKING_DIRECTORY ${HTML_PATH}
+ COMMAND git push parc gh-pages -f)
+
+ add_custom_target(documentation-install-github
+ DEPENDS ${HTML_PATH}/.git/config
+ WORKING_DIRECTORY ${HTML_PATH}
+ COMMAND git push github gh-pages -f)
+
+endif(DOXYGEN_FOUND)
diff --git a/longbow/documentation/DoxygenLayout.xml b/longbow/documentation/DoxygenLayout.xml
new file mode 100644
index 00000000..759a9cd4
--- /dev/null
+++ b/longbow/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/longbow/documentation/LaTeX Documentation/.gitignore b/longbow/documentation/LaTeX Documentation/.gitignore
new file mode 100644
index 00000000..a9f1afaf
--- /dev/null
+++ b/longbow/documentation/LaTeX Documentation/.gitignore
@@ -0,0 +1,7 @@
+.texpadtmp
+*.aux
+*.log
+*.pdf
+*.out
+*.toc
+*.synctex.gz
diff --git a/longbow/documentation/LaTeX Documentation/Abstract.tex b/longbow/documentation/LaTeX Documentation/Abstract.tex
new file mode 100644
index 00000000..0c394e76
--- /dev/null
+++ b/longbow/documentation/LaTeX Documentation/Abstract.tex
@@ -0,0 +1,7 @@
+%-
+% ABSTRACT
+%-
+%
+\Abstract{Software testing, validation, and measurable quality metics are an important element in modern software development.
+LongBow is a software framework and facility for writing software using invariants, runtime validation, unit testing, and code analysis for the C programming language.
+}
diff --git a/longbow/documentation/LaTeX Documentation/Document.tex b/longbow/documentation/LaTeX Documentation/Document.tex
new file mode 100644
index 00000000..273336ef
--- /dev/null
+++ b/longbow/documentation/LaTeX Documentation/Document.tex
@@ -0,0 +1,730 @@
+\begin{document}
+
+\flushbottom % Makes all text pages the same height
+
+\maketitle % Print the title and abstract box
+
+% Use the multicols package to a make multi-column table of contents.
+\begin{multicols}{2}
+\tableofcontents
+\end{multicols}
+
+%For a single column table of contents just use this
+%\tableofcontents % Print the contents section
+
+\thispagestyle{empty} % Removes page numbering from the first page
+
+%\newcommand{\HRule}{\rule{\linewidth}{0.5mm}} % Defines a new command for the horizontal lines, change thickness here
+
+\section{Overview} % The \section{} command stops section numbering
+
+LongBow is software to help you write better C programs. It provides:
+\begin{itemize}
+\item A run-time assertion facility to establish strict rules on the state of your program.
+\item A testing facility based on the xUnit testing model.
+\item Compile-time assistance for writing code meant to be compiled by compilers with different features.
+\end{itemize}
+
+LongBow can help you find and manage problems early, establish and maintain confidence in the correctness of your code, make collaboration easier, facilitate future change, and improve overall design.
+
+LongBow allows you to take control and establish invariant pre- and post-conditions that detect inconsistencies and unexpected results in your programs in order to find bugs and design deficiencies in the code during development rather than waiting for others to find your bugs for you.
+
+\section{Set up and installation}
+How to install, configure, link, and run LongBow.
+
+\subsection {Installation}
+Get the tar file from xxx.
+untar and do a make install.
+The resulting LongBow directory will contain the C header files, C source files, and runtime libraries needed.
+
+\subsection {Configuration}
+
+\subsubsection{LongBow with LLDB}
+The {\tt lldb} debugger is aware when C source files (not header files) are included in another source file.
+This induces a problem where the breakpoints in the included source files are not set.
+But you can configure lldb to set them: In the file {\tt \~/.lldbinit},
+add the line:
+
+\begin{lstlisting}
+settings set target.inline-breakpoint-strategy always
+process handle -p true -s false SIGABRT
+\end{lstlisting}
+
+\subsubsection{LongBow with GDB}
+LongBow uses signals to interrupt program flow when an assertion fails.
+When using gdb this will cause gdb to stop running of the test.
+This probably isn't what you want and would rather prefer that gdb just
+ignore the signal and let the LongBow unit test signal handler take care of the signal.
+To do this, you must configure gdb to ignore the signal and to allow it to pass to the program being executed.
+In the file {\tt \~/.gdbinit}, add the line:
+
+\begin{lstlisting}
+handle 6 nostop pass
+\end{lstlisting}
+
+\subsubsection{Linking and Libraries}
+There are two LongBow libraries that must be linked with the application: the primary LongBow library, (\url{liblongbow.a}) and one of the LongBow reporter libraries.
+The reporter libraries enable the reporting mechanism for Longbow.
+Currently two reporter libraries have been implemented:
+\begin{enumerate}
+\item \url{liblongbow-plaintext.a} which displays output as simple text; and
+\item \url{liblongbow-ansiterm.a} which displays output as an ANSI colorized output.
+\end{enumerate}
+
+Both display to standard output.
+
+\subsubsection{Running and Runtime Behavior}
+You can "run" Longbow in one of two ways: you can run your application with assertions turned on in order to test expected invariance during runtime; or you can run your tests using Longbow's Test Runner.
+Turning off assertions for runtime is not currently supported.
+
+\section{Programming with Assertions}
+
+Longbow's Assertions offer a way to check runtime invariance throughout your program.
+Traps are a subset of Assertions that are executed at runtime even if Assertions have been turned off during deployment. They should be used when program failure is the correct response to assertion failure.
+
+The assertion framework is based on the following design principles:
+\begin{itemize}
+\item It is intentionally simple and can be extended.
+\item You don't have to change your program design to accommodate assertions.
+\item It is designed specifically for C programs.
+\item It is based on programming with invariance.
+\item Assertions may be used only during development as a debugging aid, or in deployment as well to offer more descriptive errors to users.
+\end{itemize}
+
+
+\subsection{Designing with Assertions }
+Assertions can be used to debug code and give better information about errors to users.
+They should not be used for error handling.
+Assertions should be used to explicitly test for conditions that must be true in order for an operation to work. Examples include testing for NULL pointers, out-of-bounds array indices, and incorrect dependent relationships. Ultimately your code should work every time under all input conditions without ever triggering an assertion although passing tests don't guarantee proper design. You should aim for 100\% code coverage.
+
+Be strategic about where the assertions are located and what they test for.
+A failed assertion should be considered a bug should be treated as such.
+For example a failure to open a file is likely not a bug in your program, per se, but indicative of some other problem and programmatic error handling would probably be the best approach to handling the missing file.
+
+Assertions can be included or excluded at compile-time. In many cases, it is reasonable to keep the assertions in production releases as an aid to future bug reporting.
+
+\subsection{Using the Assertion Libraries }
+
+LongBow provides a basic set of assertions that test a condition and trigger the assertion if the condition fails to be true. When an assertion triggers the following occurs:
+\begin{itemize}
+\item An Event is created which records the kind of assertion that failed and the location of the assertion's failure.
+\item The formatted message of the failed assertion is reported via the LongBow report library.
+\item The running program is sent a {\tt SIGABRT} signal.
+\end{itemize}
+
+The following four assertions are currently supported:
+\begin{itemize}
+\item {\tt assertTrue}
+\item {\tt assertFalse}
+\item {\tt assertNull}
+\item {\ttfamily assertNotNull}
+\end{itemize}
+
+The function signatures for assertions follow the pattern:
+
+\Cfunctiondef{\tt void}{assertX}{{\it condition}, {\tt "message", ...}}
+
+Where {\tt "message"} is a printf(3) format, nul-terminated C-String that will be displayed when the assertion triggers. The ... represents the arguments that might be used to create the string.
+
+There is one C header file that must be required to use the assertion mechanism:
+\begin{itemize}
+\item \textbf{LongBow/runtime.h} is the basic header file needed for assertions.
+\end{itemize}
+
+\subsection {Using Traps}
+LongBow traps are subsets of assertions and are intended for simple error reporting.
+There is no functional difference between a trap and an assertion, however, a traps cannot be shut off during runtime so they are good to use for deployment if you plan to turn assertions off and the program should terminate when the assertion is not met.
+
+Traps take as arguments a condition and a printf(3) format C string of explanatory text along with any values necessary to format the string.
+
+A typical trap function signature is:
+
+\Cfunctiondef{\tt void}{trap{\it Kind}}{{\it condition}, {\tt "message", ...}}
+
+Where {\it Kind} represents the kind of trap (see {\tt LongBow/traps.h}.
+If the {\it condition} is evaluated to {\tt true}, the trap is triggered.
+
+where {\tt ...} is the printf format string and values.
+
+\noindent Currently supported traps are defined in \texttt{traps.h} and include:
+\begin{itemize}
+\item \textbf{trapIllegalValue:} Used for capturing failed parameter validation, for example.
+\item \textbf{trapIllegalValueIf:} Used to trap an illegal value if a condition is met.
+\item \textbf{trapNotImplemented:} Used to report and abort an unimplemented capability.
+\item \textbf{trapOutOfBounds:} Used to trap an out-of-bounds condition on an index.
+\item \textbf{trapOutOfBoundsIf:} Used to trap an out-of-bounds condition for a specific value.
+\item \textbf{trapOutOfMemory:} Used to signal that no more memory can be allocated.
+\item \textbf{trapUnexpectedState:} Used to signal that an unexpected or inconsistent state was encountered.
+\item \textbf{trapUnexpectedStateIf:} If the given condition is true, used to signal that an unexpected state was encountered.
+\item \textbf{trapUnrecoverableState:} Used to report an unrecoverable state in program execution.
+\end{itemize}
+
+\subsection{Examples }
+
+\paragraph {assertNotNull example}
+
+\begin{lstlisting}
+#include <LongBow/assertions>
+#include <unistd.h>
+#include <string.h>
+
+void
+function(char *pointer)
+{
+ assertNotNull(pointer, "The pointer cannot be NULL.");
+
+ write(1, pointer, strlen(pointer));
+}
+
+int
+main(int argc, char *argv[])
+{
+ function(0);
+}
+\end{lstlisting}
+
+
+In this case the {\tt assertNotNull} will trigger and the program will immediately terminate with the following output:
+
+\begin{lstlisting}
+Assert pointer.c:8 function() pointer != NULL The pointer cannot be NULL.
+0 pointer 0x0000000107840d4c function + 188
+1 pointer 0x0000000107840dd1 main + 33
+2 libdyld.dylib 0x00007fff887595fd start + 1
+
+\end{lstlisting}
+
+\paragraph {assertTrue example}
+
+\begin{lstlisting}
+LONGBOW_TEST_CASE(Global, myTest)
+{
+ struct timeval timeval;
+ timeval.tv_sec = 0;
+ timeval.tv_usec = 1000;
+
+ char *expected = "0.001000";
+ char *actual = parcTime\_FormatTimeval(timeval);
+ assertTrue(strcmp(expected, actual) == 0, "Expected \%s, actual \%s", expected, actual);
+ parc_free(actual);
+}
+ \end{lstlisting}
+
+\paragraph{Example using assertNull, assertNotNull, and assertTrue}
+
+\begin{lstlisting}
+static void
+parcDeque_AssertInvariants(const PARCDeque *deque)
+{
+ assertNotNull(deque, "Parameter cannot be null.");
+ if (deque->head != NULL) {
+ assertTrue(deque->size != 0, "PARCDeque head is not-null, but size is zero.");
+ assertNotNull(deque->tail, "PARCDeque head is not-null, but tail is null.");
+ parcDequeNode_AssertInvariants(deque->head);
+ parcDequeNode_AssertInvariants(deque->tail);
+ } else {
+ assertNull(deque->tail, "PARCDeque head is null, but tail is not null.");
+ assertTrue(deque->size == 0, "PARCDeque head is null, but size is not zero.");
+ }
+}
+
+\end{lstlisting}
+
+\paragraph {assertFalse example}
+\begin{lstlisting}
+RtaCommand *
+rtaCommand_Read(int fd)
+{
+ ssize_t readlen;
+ uint32_t netbyteorder;
+ size_t len;
+ char *p;
+ RtaCommand *command;
+
+ readlen = read(fd, &netbyteorder, 4);
+ assertFalse(readlen < 0, "socket read error: \%s\n", strerror(errno));
+ assertTrue(readlen == 4, "Partial read on command length");
+
+ len = ntohl(netbyteorder);
+ p = parc_malloc(len);
+ readlen = read(fd, p, len);
+ assertTrue(readlen == len, "Partial read on command");
+
+ command = rtaCommand_Parse(p);
+ parc_free(p);
+ return command;
+}
+\end{lstlisting}
+
+
+\section{Unit testing}
+Longbow provides an xUnit-style unit testing framework. The framework is a mechanism for organizing and running trees of test code. It is organized hierarchically into three components: a Test Runner, Test Fixtures, and Test Cases.
+
+A Test Runner file is associated 1:1 with a C source file, with the word "test\_" prepended on the C source file name. For example, the Test Runner file for {\tt parc\_Buffer.c} would be {\tt test\_parc\_Buffer.c}.
+This file contains all of the Test Fixtures and Test Cases needed to test the associated C source file.
+
+Each Test Runner will run a set of Test Fixtures.
+Test Fixtures are an organizational unit that allows you to group your Test Cases.
+The grouping may be done by functionality, by static vs non static functions, or by any other organizing principle that you choose.
+
+A Test Fixture runs a set of Test Cases each of which is responsible for testing some aspect of the C module.
+
+Tests are run in the order they are defined.
+The Test Runner will start with Test Fixture1 and all of its Test Cases, move on to Test Fixture2 and its Test Cases etc. Tests should be idempotent, however, and not assume any particular order or be dependent on each other.
+They should not leave state such that the next Test Case inherits that state.
+
+%\subsection{Designing tests }
+%\textcolor{red}{Put something here}
+
+\subsection{Writing tests with the Test Runner module }
+\subsubsection{Test Runners}
+A Test Runner is the top-level executable unit in a test.
+It is responsible for establishing the necessary state for the set of tests it contains, executing the tests via Test Fixtures and Test Cases, and tearing down state when the tests have completed.
+
+A Test Runner requires the following header files:
+\begin{itemize}
+\item \textbf{LongBow/runtime.h} is the basic header file needed for assertions and testing.
+\item \textbf{LongBow/unit-test.h} is the basic header file needed for testing.
+\item \textbf{LongBow/compiling.h} is used when you have code that needs to work across multiple compilers - it contains the matrix of compiler and / you are using.
+\end{itemize}
+
+\noindent The source code of a Test Runner has the following basic structure:
+
+\begin{lstlisting}
+#include <LongBow/testing.h>
+
+LONGBOW_TEST_RUNNER(myRunner)
+{
+}
+
+LONGBOW_TEST_RUNNER_SETUP(myRunner)
+{
+ // Code to set up required state
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(myRunner)
+{
+ //Code to clean up state
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+\end{lstlisting}
+
+
+Each of these functions has a local variable - {\tt LongBowRunner *testRunner} - which may be used to manipulate the clipboard (as an example). The Text Fixtures and Test Cases launched by the Test Runner will have access to this variable as well as their own local variable. Thus a Test Fixture will have access to the {\tt testRunner} that is passed to it as well as its own {\tt LongBowFixture *testFixture} and a Test Case will have access to {\tt testRunner, testFixture} and its own {\tt LongBowCase *testCase}.
+
+\subsubsection{Test Fixtures}
+
+A Test Fixture is a subcomponent which has the same structure as a Test Runner.
+The following code adds Test Fixture to a Test Runner:
+
+\begin{lstlisting}
+LONGBOW_TEST_RUNNER(myRunner)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+\end{lstlisting}
+
+
+Like the Test Runner, it is responsible for setting up and tearing down state needed by the Test Cases.
+
+\begin{lstlisting}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, myTest);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+\end{lstlisting}
+
+\subsubsection{Test Cases}
+Test Cases are the leaf nodes of the testing tree. Each Test Case tests one aspect of the C module.
+
+\paragraph {Handling Test Case state safely}
+
+Every Test Case has access to a private \"clipboard\" that contains data shared between the Test Case and the set up and teardown functions of its encapsulating Test Fixture.
+This shared state is used to provide specific environment or initialized variables for the test and for the test to communicate specialized information to the teardown function.
+
+For example, a Test Case which is expected to fail as the result of testing a failure condition might exit without releasing resources which are left in an unsafe state.
+As multiple tests may be run in one process, it is important to clean these up before launching the next test.
+
+The following example demonstrates the clipboard mechanism:
+\begin{itemize}
+\item{The Test Fixture setup function allocates the necessary resources and puts references to them into the clipboard.}
+\item{The Test Case gets these references, uses them, and fails.}
+\item{The Test Fixture tear-down function obtains the resources from the clipboard and deallocates them.}
+\end{itemize}
+
+\subsubsection {Test Runner Example}
+The following is an example of a test file :
+
+\begin{lstlisting}
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+LONGBOW_TEST_RUNNER(testClipboard)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(testClipboard)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(testClipboard)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, testClipboard);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ char *testData = strdup("Hello World");
+ longBowTest Case_SetClipBoardData(testCase, testData, free);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, testClipboard)
+{
+ char *testData = longBowTest Case_GetClipBoardData(testCase);
+ printf("Shared state '%s'\n", testData);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(testClipboard);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTest Runner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+\end{lstlisting}
+
+\subsubsection {Testing for Successful Failure}
+Testing for success is straightforward but we also may have to test that something fails when it is supposed to.
+This section describes how to test for an expected non-success result.
+
+To compose a Test Case that expects a result other than success, use the {\tt LONGBOW\_TEST\_CASE\_EXPECTS} function which takes the expected event as a parameter and completes. The example below shows the capture of a successful segmentation fault.
+
+
+\begin{lstlisting}
+#include <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(LongBow)
+{
+ LONGBOW_RUN_TEST_FIXTURE(MyFixture);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(LongBow)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(LongBow)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(MyFixture)
+{
+ LONGBOW_RUN_TEST_CASE(MyFixture, alwaysSEGV);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(MyFixture)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(MyFixture)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(MyFixture, alwaysSEGV, .event = &LongBowEventSIGSEGV)
+{
+ int *p = 0;
+ int i = *p;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(LongBow);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTest Runner_Destroy(&testRunner);
+
+ exit(status);
+}
+
+\end{lstlisting}
+
+\subsection{Running tests}
+
+The overall process for writing and running your tests:
+\begin{itemize}
+\item Write a Test Runner file for every .c file that completely tests all of the code container in the .c file. This filename should be "test\_" prepended to the name of the file you are testing.
+\item Compile the Test Runner file with one of:
+\begin {itemize}
+\item -llongbow -llongbow-ansiterm
+\item -llongbow -llongbow-textplain
+\end{itemize}
+\item Execute the Test Runner.
+\end{itemize}
+
+
+\subsection{Examples }
+
+Here is an example of a C source file and its associated Test file. Tutorial.c is a small C program which simply provides an uninteresting but useful exemplar of the test framework.
+
+
+\noindent \textbf{Tutorial.c}
+
+\begin{lstlisting}
+#include <unistd.h>
+#include <stdbool.h>
+#include <signal.h>
+
+static bool
+_privateFunction()
+{
+ return true;
+}
+
+bool
+alwaysSucceed()
+{
+ return _privateFunction();
+}
+
+bool
+alwaysFail()
+{
+ return false;
+}
+
+bool
+blowUp()
+{
+ char *p = 0;
+ *p = 0;
+
+ return true;
+}
+
+\end{lstlisting}
+
+The following code is the test file for the Tutorial.c. Note that the file name is simply the C source file name with "test\_" prepended. In this example, the Test Runner divides the Test Cases into two Test Fixtures: one to focus on the Static functions and one to focus on the Global functions.
+
+\noindent \textbf{test\_Tutorial.c}
+\begin{lstlisting}
+
+#include "tutorial.c"
+
+#include <LongBow/unit-test.h>
+
+
+LONGBOW_TEST_RUNNER(myTutorialTest)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, alwaysSucceed);
+ LONGBOW_RUN_TEST_CASE(Global, alwaysFail);
+ LONGBOW_RUN_TEST_CASE(Global, blowUp);
+
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, alwaysSucceed)
+{
+ bool result = alwaysSucceed();
+
+ assertTrue(result, "This test must always succeed.");
+}
+
+LONGBOW_TEST_CASE(Global, alwaysFail)
+{
+ bool result = alwaysFail();
+
+ assertTrue(result, "This test will fail.");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, blowUp, .event = &LongBowEventSIGSEGV)
+{
+ blowUp();
+
+ assertTrue(false, "This will not be executed");
+}
+
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, _privateFunction);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Static, _privateFunction)
+{
+ bool result = _privateFunction();
+
+ assertTrue(result, "This test must always succeed.");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(myTutorialTest);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+
+ longBowTest Runner_Destroy(&testRunner);
+ exit(status);
+}
+
+\end{lstlisting}
+
+\section {Compiling and Compiler Support}
+LongBow consolidates a variety of compile-time options that you include in your code.
+
+For example, the C99 standard defines the pragma operator and various compilers support this in various ways.
+
+\section{The LongBow Reporter}
+The Longbow reporter offers a more user-friendly option for viewing the output of the running tests. In addition to linking with the primary LongBow library ({\tt liblongbow.a}), you also need to link with one of the following reporting libraries to control presentation of the test output.
+\begin{itemize}
+\item {\bf liblongbow-ansiterm.a} This option produces output that is color coded to indicate the degree of success: green for a successful test; yellow for warnings; and red for failure.
+\item {\bf liblongbow-plaintext.a} This option produces plain text output.
+\item {\bf liblongbow-json.a} This option is in development and will produce output in JSON format.
+\end{itemize}
+
+
+
+\section {Appendices}
+\subsection {Function Documentation}
+The following modules are included in LongBow:
+\begin {itemize}
+\item \textbf{Runtime:} LongBow functions and macros for runtime.
+\item \textbf{Testing:} LongBow functions and macros for writing tests.
+\item \textbf{Internals:} LongBow functions and macros used internally.
+\item \textbf{Reporting:} LongBow functions and definitions for writing report libraries.
+\item \textbf{Performance testing:} LongBow functions and definitions for writing performance tests.
+\end{itemize}
+
+\paragraph {Runtime}
+LongBow runtime support consists primarily of assertions and traps. Developers insert assertions to insist that certain conditions are true before permitting the program to continue. If the assertion fails, the program is abnormally terminated. It uses the following files:
+
+\begin{itemize}
+\item {\bf assertions.h:} Runtime and Test Assertions.
+ \item {\bf longBow\_EventType.h:} LongBow Events and Support.
+ \item {\bf longBow\_Runtime.h:} The LongBow Runtime support.
+ \item {\bf runtime.h:} LongBow Runtime Support.
+ \item {\bf traps.h:} Runtime and Test Traps.
+\end{itemize}
+
+
+\paragraph {Testing}
+LongBow testing support consists of macros and ancillary functions to implement an xUnit style of writing and running tests. Test writers create a LONGBOW\_TEST\_RUNNER function which invokes one or more LONGBOW\_TEST\_FIXTURE functions, each of which invoke a specific LONGBOW\_TEST\_CASE. It uses the following files:
+
+\begin{itemize}
+\item {\bf longBow\_EventType.h:} LongBow Events and Support.
+ \item {\bf longBow\_Main.h:} A main() function to run one or more LongBow Test Runners.
+ \item {\bf longBow\_OpenFile.h:} LongBow support for files and file descriptors.
+ \item {\bf longBow\_Runner.h:} LongBow Test Runner Support.
+ \item {\bf longBow\_Status.h} A simple status representation for a LongBow Test Case.
+ \item {\bf longBow\_Test CaseClipBoard.h:} LongBow Clipboard shared between the setup, test case, and teardown.
+ \item {\bf longBow\_UnitTesting.h} Unit Testing Support. .
+ \item {\bf testing.h:} LongBow testing functionality.
+ \item {\bf unit-test.h} LongBow Unit Test Support.
+\end{itemize}
+
+\paragraph {Internals}
+LongBow functions and macros used internally.
+It uses the following files:
+
+\begin{itemize}
+ \item {\bf longBow\_ArrayList.h} A simple, list implementation using a dynamic array.
+ \item {\bf longBow\_Backtrace.h} Support for Stack Traces.
+ \item {\bf longBow\_Configuration.h} Support for LongBow Configuration.
+ \item {\bf longBow\_Debugging.h} Support for LongBow and Application Debugging.
+ \item {\bf longBow\_Event.h} LongBow Event Support.
+ \item {\bf longBow\_EventType.h} LongBow Events and Support.
+ \item {\bf longBow\_Fixture.h} Manage the execution of Test Cases.
+ \item {\bf longBow\_Location.h} LongBow Source File Location.
+ \item {\bf longBow\_Test Case.h} The interface and supporting functionality of a LongBow Test Case.
+ \item {\bf longBow\_Test CaseResult.h} LongBow Test Case Results.
+\end{itemize}
+
+
+ \paragraph {Reporting}
+LongBow functions and definitions for writing report libraries.
+It uses the following header files:
+
+\begin{itemize}
+ \item {\bf longBow\_ReportANSITerminal\_Runtime.h} ANSI Terminal Reporting.
+\item {\bf longBow\_Report\_Runtime.h} The LongBow Runtime Report Generator.
+\item {\bf longBow\_Report\_Testing.h} The LongBow Test Report Generator.
+\end{itemize}
+
+
+ \paragraph {Performance Testing}
+Using LongBow for performance tests.
+
+\end{document}
diff --git a/longbow/documentation/LaTeX Documentation/LongBow.tex b/longbow/documentation/LaTeX Documentation/LongBow.tex
new file mode 100644
index 00000000..8f8a7e60
--- /dev/null
+++ b/longbow/documentation/LaTeX Documentation/LongBow.tex
@@ -0,0 +1,37 @@
+%----------------------------------------------------------------------------------------
+% PACKAGES AND OTHER DOCUMENT CONFIGURATIONS
+%----------------------------------------------------------------------------------------
+\documentclass[fleqn,12pt]{PARCOneColumn} % 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{urlcolor}{RGB}{0,0,90} % Color of the article title and sections
+\definecolor{citecolor}{RGB}{0,0,90} % Color of the article title and sections
+\definecolor{linkcolor}{RGB}{0,0,90} % Color of the article title and sections
+\usepackage{hyperref} % Required for hyperlinks
+\hypersetup{hidelinks,
+colorlinks,
+breaklinks=true,
+urlcolor=urlcolor,
+citecolor=citecolor,
+linkcolor=linkcolor,
+bookmarksopen=false,
+pdftitle={Title},
+pdfauthor={Author}}
+%
+\input{Packages}
+%
+\input{title}
+%
+\input{abstract}
+%
+\input{document}
diff --git a/longbow/documentation/LaTeX Documentation/PARCOneColumn.cls b/longbow/documentation/LaTeX Documentation/PARCOneColumn.cls
new file mode 100644
index 00000000..a58d3409
--- /dev/null
+++ b/longbow/documentation/LaTeX Documentation/PARCOneColumn.cls
@@ -0,0 +1,288 @@
+% 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{PARCOneColumn}[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{\small\sffamily\bfseries\@LeftFooter}%
+\cfoot{\small\sffamily\bfseries\@CenterFooter}%
+\rfoot{\small\sffamily\bfseries\@RightFooter}%
+\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{\LeftFooter}[1]{\def\@LeftFooter{#1}}
+\newcommand{\CenterFooter}[1]{\def\@CenterFooter{#1}}
+\newcommand{\RightFooter}[1]{\def\@RightFooter{#1}}
+
+\LeftFooter{}
+\CenterFooter{}
+\RightFooter{}
+%
+% ---------------------------------------------------------------------
+%
+\newcommand{\NormalSansBold}[1]{\normalsize\sffamily\bfseries #1}
+\newcommand{\SmallSansBold}[1]{\small\sffamily\bfseries #1}
+\newcommand{\MastHeadText}[1]{\sffamily\fontsize{10}{12}\selectfont #1}
+%
+\newcommand{\MakePARCMastHead}[1]{
+\setlength{\tabcolsep}{0pt}
+\begin{tabular*}{\textwidth}{l @{\extracolsep{\fill}} p{0.618\textwidth} }
+ \includegraphics[width=110pt]{parc_black_solid}&\vbox{\raggedleft\MastHeadText{#1}\vskip0.24mm}\\
+\end{tabular*}
+\vskip-5mm\hrule
+}
+%
+\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}{%
+\centering{%
+\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/longbow/documentation/LaTeX Documentation/Packages.tex b/longbow/documentation/LaTeX Documentation/Packages.tex
new file mode 100644
index 00000000..90f5f6db
--- /dev/null
+++ b/longbow/documentation/LaTeX Documentation/Packages.tex
@@ -0,0 +1,58 @@
+%
+% Specify packages that you need in this file.
+% If a package requires configuration, do that here.
+\usepackage{lipsum}
+\usepackage{tcolorbox}
+
+\usepackage{listings}
+
+\definecolor{goodCodeColor}{rgb}{1.0,1.0,1.0}
+\definecolor{badCodeColor}{rgb}{1.0,0.95,0.95}
+\definecolor{mygreen}{rgb}{0,0.6,0}
+\definecolor{mygray}{rgb}{0.5,0.5,0.5}
+\definecolor{mymauve}{rgb}{0.58,0,0.82}
+\lstset{ %
+ backgroundcolor=\color{goodCodeColor}, % choose the background color; you must add \usepackage{color} or \usepackage{xcolor}
+ basicstyle=\tt\small, % the size of the fonts that are used for the code
+ breakatwhitespace=false, % sets if automatic breaks should only happen at whitespace
+ breaklines=true, % sets automatic line breaking
+ captionpos=b, % sets the caption-position to bottom
+ commentstyle=\color{mygreen}, % comment style
+ deletekeywords={...}, % if you want to delete keywords from the given language
+ escapeinside={@}{@}, % if you want to add LaTeX within your code
+ extendedchars=true, % lets you use non-ASCII characters; for 8-bits encodings only, does not work with UTF-8
+ frame=single, % adds a frame around the code
+ keepspaces=true, % keeps spaces in text, useful for keeping indentation of code (possibly needs columns=flexible)
+ keywordstyle=\color{blue}, % keyword style
+ language=C, % the language of the code
+ morekeywords={*,...}, % if you want to add more keywords to the set
+ numbers=left, % where to put the line-numbers; possible values are (none, left, right)
+ numbersep=5pt, % how far the line-numbers are from the code
+ numberstyle=\tiny\color{mygray}, % the style that is used for the line-numbers
+ rulecolor=\color{black}, % if not set, the frame-color may be changed on line-breaks within not-black text (e.g. comments (green here))
+ showspaces=false, % show spaces everywhere adding particular underscores; it overrides 'showstringspaces'
+ showstringspaces=false, % underline spaces within strings only
+ showtabs=false, % show tabs within strings adding particular underscores
+ stepnumber=2, % the step between two line-numbers. If it's 1, each line will be numbered
+ stringstyle=\color{mymauve}, % string literal style
+ tabsize=2, % sets default tabsize to 2 spaces
+ title=\lstname % show the filename of files included with \lstinputlisting; also try caption instead of title
+}
+
+
+\newcommand{\functionBox}[1]{%
+ \begin{tcolorbox}[boxrule=0.5pt,arc=4pt,left=6pt,right=6pt,top=6pt,bottom=6pt,boxsep=0pt]
+ #1
+ \end{tcolorbox}}
+
+\newcommand{\Returns}[2]{{\bf Returns:} #1\hfil\break\begin{tabular}{l r l} #2 \end{tabular}}
+\newcommand{\retval}[2]{\hbox to1em{} & {#1} & {#2}\\ }
+
+\newcommand{\Cfunctionparam}[3]{\hbox to1em{} & #1 & {\tt #2} & #3 \\}
+\newcommand{\paramdef}[1]{\begin{tabular}{ r r l l } #1\end{tabular}\hfil\break}
+\newcommand{\Cfunctiondef}[3]{\functionBox{{#1} {\tt #2(}\hfil\break\paramdef{#3}{\tt )}}}
+
+\newcommand{\Cfunctionref}[1]{{\tt #1()}}
+\newcommand{\functionAbstract}[1]{#1\hfil\break}
+\newcommand{\functionReturns}[2]{{\bf Returns:}\hfil\break\indent\hbox to3em{} #1: #2\hfil\break}
+\newcommand{\NULL}{{\tt NULL }}
diff --git a/longbow/documentation/LaTeX Documentation/Title.tex b/longbow/documentation/LaTeX Documentation/Title.tex
new file mode 100644
index 00000000..b05521b7
--- /dev/null
+++ b/longbow/documentation/LaTeX Documentation/Title.tex
@@ -0,0 +1,13 @@
+%----------------------------------------------------------------------------------------
+% ARTICLE INFORMATION
+%----------------------------------------------------------------------------------------
+\Masthead{Networking and Distributed Systems\\Computing Science Laboratory\\Copyright 2014}
+
+\PaperTitle{LongBow}{Write Better C Programs} % 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{Software Development --- Software Testing} % Keywords - if you don't want any simply remove all the text between the curly brackets
+\newcommand{\keywordname}{Keywords} % Defines the keywords heading name
diff --git a/longbow/documentation/LaTeX Documentation/old/Longbow_documentation.tex b/longbow/documentation/LaTeX Documentation/old/Longbow_documentation.tex
new file mode 100644
index 00000000..5db370c2
--- /dev/null
+++ b/longbow/documentation/LaTeX Documentation/old/Longbow_documentation.tex
@@ -0,0 +1,769 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Simple Sectioned Essay Template
+% LaTeX Template
+%
+% This template has been downloaded from:
+% http://www.latextemplates.com
+%
+% Note:
+% The \lipsum[#] commands throughout this template generate dummy text
+% to fill the template out. These commands should all be removed when
+% writing essay content.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%----------------------------------------------------------------------------------------
+% PACKAGES AND OTHER DOCUMENT CONFIGURATIONS
+%----------------------------------------------------------------------------------------
+
+\documentclass[12pt]{article} % Default font size is 12pt, it can be changed here
+
+\usepackage{graphicx} % Required for including pictures
+
+\usepackage{float} % Allows putting an [H] in \begin{figure} to specify the exact location of the figure
+\usepackage{wrapfig} % Allows in-line images such as the example fish picture
+
+\usepackage{lipsum} % Required to insert dummy text
+\usepackage{hyperref}
+
+\usepackage{wrapfig}
+\usepackage[toc]{appendix}
+\usepackage{url}
+\usepackage{mdframed}
+\usepackage{listings}
+\lstset{ %
+basicstyle=\tt\footnotesize,
+breakatwhitespace=false,
+ breaklines=true.
+ tabsize=4
+}
+
+\usepackage{float}
+\restylefloat{table}
+
+
+\linespread{1.2} % Line spacing
+
+%\setlength\parindent{0pt} % Uncomment to remove all indentation from paragraphs
+
+\graphicspath{{Pictures/}} % Specifies the directory where pictures are stored
+
+\begin{document}
+
+%----------------------------------------------------------------------------------------
+% TITLE PAGE
+%----------------------------------------------------------------------------------------
+\begin{titlepage}
+
+\newcommand{\HRule}{\rule{\linewidth}{0.5mm}} % Defines a new command for the horizontal lines, change thickness here
+
+\center % Center everything on the page
+
+
+\HRule \\[0.4cm]
+{ \huge \bfseries Longbow Documentation}\\[0.4cm] % Title of your document
+\HRule \\[1.5cm]
+
+\begin{minipage}{0.4\textwidth}
+\begin{flushleft} \large
+\emph{Author:}\\
+Glenn \textsc{Scott} % Your name
+\end{flushleft}
+\end{minipage}
+~
+
+{\large \today}\\[3cm] % Date, change the \today to a set date if you want to be precise
+
+%\includegraphics{Logo}\\[1cm] % Include a department/university logo - this will require the graphicx package
+
+\vfill % Fill the rest of the page with whitespace
+
+\end{titlepage}
+
+%----------------------------------------------------------------------------------------
+% TABLE OF CONTENTS
+%----------------------------------------------------------------------------------------
+
+\tableofcontents % Include a table of contents
+\newpage
+\section{Overview} % The \section{} command stops section numbering
+
+LongBow is software to help you write better C programs. It provides:
+\begin{itemize}
+\item a run-time assertion facility to establish strict rules on the state of your program.
+\item a testing facility based on the xUnit testing model.
+\item compile-time assistance for writing code meant to be compiled by compilers with different features.
+\end{itemize}
+
+LongBow can help you find and manage problems early, establish and maintain confidence in the correctness of your code, make collaboration easier, facilitate future change, and improve overall design.
+
+LongBow allows you to take control and establish invariant pre- and post-conditions that detect inconsistencies and unexpected results in your programs in order to find bugs and design deficiencies in the code during development rather than waiting for others to find your bugs for you.
+
+\section{Set up and installation}
+How to install, configure, link, and run LongBow.
+\subsection {Installation}
+Get the tar file from xxx.
+untar and do a make install.
+The resulting LongBow directory will contain the C header files, C source files, and runtime libraries needed.
+
+\subsection {Configuration}
+
+\subsubsection{LongBow with LLDB}
+The {\tt lldb} debugger is aware when C files are included. This induces a problem where the breakpoints in the included files are not set. But you can configure lldb to set them: In ~/.lldbinit settings set target.inline-breakpoint-strategy always
+
+
+\hfill \texttt{settings set target.inline-breakpoint-strategy always} \hfill \break
+
+\subsubsection{LongBow with GDB}
+LongBow uses signals to interrupt program flow when an assertion fails. When using gdb this will cause gdb to stop running of the test. This probably isn?t what you want and would rather prefer that gdb just ignore the signal and let the LongBow unit test signal handler take care of the signal. To do this, you must configure gdb to ignore the signal and to allow it to pass to the program being executed.
+
+
+\hfill \texttt{handle 6 nostop pass} \hfill \break
+
+\subsubsection{Linking and Libraries}
+There are two LongBow libraries that must be linked with the application: the primary LongBow library, (\url{liblongbow.a}) and one of the LongBow reporter libraries. The reporter libraries enable the reporting mechanism for Longbow. Currently two reporter libraries have been implemented: \url{liblongbow-plaintext.a} which displays output as simple text; and \url{liblongbow-ansiterm.a} which displays output as an ANSI colorized output. Both display to standard output.
+
+\subsubsection{Running and Runtime Behavior}
+You can "run" Longbow in one of two ways: you can run your application with assertions turned on in order to test expected invariance during runtime; or you can run your tests using Longbow's Test Runner. Turning off assertions for runtime is not currently supported.
+
+\section{Programming with Assertions}
+
+ Longbow's Assertions offer a way to check runtime invariance throughout your program. Traps are a subset of Assertions that are executed at runtime even if Assertions have been turned off during deployment. They should be used when program failure is the correct response to assertion failure.
+
+The assertion framework is based on the following design principles:
+\begin{itemize}
+\item It is intentionally simple and can be extended.
+\item You don't have to change your program design to accommodate assertions.
+\item It is designed specifically for C programs.
+\item It is based on programming with invariance.
+\item Assertions may be used only during development as a debugging aid, or in deployment as well to offer more descriptive errors to users.
+\end{itemize}
+
+
+\subsection{Designing with Assertions }
+Assertions can be used to debug code and give better information about errors to users. They should not be used for error handling. Assertions should be used to explicitly test for conditions that must be true in order for an operation to work. Examples include testing for NULL pointers, out-of-bounds array indices, and incorrect dependent relationships. Ultimately your code should work every time under all input conditions without ever triggering an assertion although passing tests don't guarantee proper design. You should aim for 100\% code coverage.
+
+Be strategic about where the assertions are located and what they test for.
+A failed assertion should be considered a bug should be treated as such. For example a failure to open a file is likely not a bug in your program, per se, but indicative of some other problem and programmatic error handling would probably be the best approach to handling the missing file.
+
+Assertions can be included or excluded at compile-time. In many cases, it is reasonable to keep the assertions in production releases as an aid to future bug reporting.
+
+\subsection{Using the Assertion Libraries }
+
+LongBow provides a basic set of assertions that test a condition and trigger the assertion if the condition fails to be true. When an assertion triggers the following occurs:
+\begin{itemize}
+\item An Event is created which records the kind of assertion that failed and the location of the assertion's failure.
+\item The formatted message of the failed assertion is reported via the LongBow report library.
+\item The running program is sent a SIGABRT signal.
+\end{itemize}
+
+The following four assertions are currently supported:
+\begin{itemize}
+\item assertTrue
+\item assertFalse
+\item assertNull
+\item assertNotNull
+\end{itemize}
+
+The function signatures are:
+
+\hfill \texttt{void assertX(condition, "\_\_\_",...);} \hfill \break
+where "\_\_\_" is the printf null-terminated C-String that will be displayed when the assertion triggers. The ... represents the arguments that might be used to create the string.
+
+There are two basic C header files that are needed:
+\begin{itemize}
+\item \textbf{LongBow/runtime.h} is the basic header file needed for assertions and testing.
+\item \textbf{LongBow/compiling.h} is used when you have code that needs to work across multiple compilers.
+\end{itemize}
+
+\subsection {Using Traps}
+LongBow traps are subsets of assertions and are intended for simple error reporting. There is no functional difference between a trap and an assertion, however, Traps cannot be shut off during runtime so they are good to use for deployment if you plan to turn assertions off and the program should terminate when the assertion is not met.
+
+Traps take as arguments a condition and a printf(3) format string of explanatory text along with any required values. A typical trap is called with:
+
+{\tt trap (condition, ...) }
+
+where {\tt ...} is the printf format string and values.
+
+\noindent Currently supported traps are defined in \texttt{traps.h} and include:
+\begin{itemize}
+\item \textbf{trapIllegalValue:} Used for capturing failed parameter validation, for example.
+\item \textbf{trapIllegalValueIf:} Used to trap an illegal value if a condition is met.
+\item \textbf{trapNotImplemented:} Used to report and abort an unimplemented capability.
+\item \textbf{trapOutOfBounds:} Used to trap an out-of-bounds condition on an index.
+\item \textbf{trapOutOfBoundsIf:} Used to trap an out-of-bounds condition for a specific value.
+\item \textbf{trapOutOfMemory:} Used to signal that no more memory can be allocated.
+\item \textbf{trapUnexpectedState:} Used to signal that an unexpected or inconsistent state was encountered.
+\item \textbf{trapUnexpectedStateIf:} If the given condition is true, used to signal that an unexpected state was encountered.
+\item \textbf{trapUnrecoverableState:} Used to report an unrecoverable state in program execution.
+\end{itemize}
+
+
+
+
+\subsection{Examples }
+
+\paragraph {assertNotNull example}
+\paragraph {assertNotNull example}
+
+\begin{lstlisting}
+#include <LongBow/assertions>
+#include <unistd.h>
+#include <string.h>
+
+void
+function(char *pointer)
+{
+ assertNotNull(pointer, "The pointer cannot be NULL.");
+
+ write(1, pointer, strlen(pointer));
+}
+
+int
+main(int argc, char *argv[])
+{
+ function(0);
+}
+\end{lstlisting}
+
+
+In this case the assertNotNull will trigger and the program will immediately terminate with the following output:
+
+\begin{lstlisting}
+Assert pointer.c:8 function() pointer != NULL The pointer cannot be NULL.
+0 pointer 0x0000000107840d4c function + 188
+1 pointer 0x0000000107840dd1 main + 33
+2 libdyld.dylib 0x00007fff887595fd start + 1
+
+\end{lstlisting}
+
+\paragraph {assertTrue example}
+ \paragraph {assertTrue example}
+
+ \begin{lstlisting}
+ LONGBOW_TEST_CASE(Global, myTest)
+{
+ struct timeval timeval;
+ timeval.tv_sec = 0;
+ timeval.tv_usec = 1000;
+
+ char *expected = "0.001000";
+ char *actual = parcTime\_FormatTimeval(timeval);
+ assertTrue(strcmp(expected, actual) == 0, "Expected \%s, actual \%s", expected, actual);
+ parc_free(actual);
+}
+ \end{lstlisting}
+
+\paragraph {Example using assertNull, assertNotNull, and assertTrue}
+ \paragraph {Example using assertNull, assertNotNull, and assertTrue}
+
+ \begin{lstlisting}
+ static void
+parcDeque_AssertInvariants(const PARCDeque *deque)
+{
+ assertNotNull(deque, "Parameter cannot be null.");
+ if (deque->head != NULL) {
+ assertTrue(deque->size != 0, "PARCDeque head is not-null, but size is zero.");
+ assertNotNull(deque->tail, "PARCDeque head is not-null, but tail is null.");
+ parcDequeNode_AssertInvariants(deque->head);
+ parcDequeNode_AssertInvariants(deque->tail);
+ } else {
+ assertNull(deque->tail, "PARCDeque head is null, but tail is not null.");
+ assertTrue(deque->size == 0, "PARCDeque head is null, but size is not zero.");
+ }
+}
+
+\end{lstlisting}
+
+\paragraph {assertFalse example}
+\paragraph {assertFalse example}
+ \begin{lstlisting}
+RtaCommand *
+rtaCommand_Read(int fd)
+{
+ ssize_t readlen;
+ uint32_t netbyteorder;
+ size_t len;
+ char *p;
+ RtaCommand *command;
+
+ readlen = read(fd, &netbyteorder, 4);
+ assertFalse(readlen < 0, "socket read error: %s\n", strerror(errno));
+ assertTrue(readlen == 4, "Partial read on command length");
+
+ len = ntohl(netbyteorder);
+ p = parc_malloc(len);
+ readlen = read(fd, p, len);
+ assertTrue(readlen == len, "Partial read on command");
+
+ command = rtaCommand_Parse(p);
+ parc_free(p);
+ return command;
+}
+\end{lstlisting}
+
+
+\section{Unit testing}
+Longbow provides an xUnit-style unit testing framework. The framework is a mechanism for organizing and running trees of test code. It is organized hierarchically into three components: a Test Runner, Test Fixtures, and Test Cases.
+
+A Test Runner file is associated 1:1 with a C source file, with the word "test\_" prepended on the C source file name. For example, the Test Runner file for parc\_Buffer.c would be test\_parc\_Buffer.c. This file contains all of the Test Fixtures and Test Cases needed to test the associated C source file.
+
+ Each Test Runner will run a set of Test Fixtures. Test Fixtures are an organizational unit that allows you to group your Test Cases. The grouping may be done by functionality, by static vs non static functions, or by any other organizing principle that you choose.
+
+ A Test Fixture runs a set of Test Cases each of which is responsible for testing some aspect of the C module.
+
+Tests are run in the order they are defined. The Test Runner will start with Test Fixture1 and all of its Test Cases, move on to Test Fixture2 and its Test Cases etc. Tests should be idempotent, however, and not assume any particular order or be dependent on each other. They should not leave state such that the next Test Case inherits that state.
+
+\subsection{Designing tests }
+\textcolor{red}{Put something here}
+
+\subsection{Writing tests with the Test Runner module }
+\subsubsection{Test Runners}
+A Test Runner is the top-level executable unit in a test. It is responsible for establishing the necessary state for the set of tests it contains, executing the tests via Test Fixtures and Test Cases, and tearing down state when the tests have completed.
+
+A Test Runner requires the following header files:
+\begin{itemize}
+\item \textbf{LongBow/runtime.h} is the basic header file needed for assertions and testing.
+\item \textbf{LongBow/unit-test.h} is the basic header file needed for testing.
+\item \textbf{LongBow/compiling.h} is used when you have code that needs to work across multiple compilers - it contains the matrix of compiler and / you are using.
+\end{itemize}
+
+\noindent The source code of a Test Runner has the following basic structure:
+
+\begin{lstlisting}
+#include <LongBow/testing.h>
+
+LONGBOW_TEST_RUNNER(myRunner)
+{
+}
+
+LONGBOW_TEST_RUNNER_SETUP(myRunner)
+{
+ // Code to set up required state
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(myRunner)
+{
+ //Code to clean up state
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+\end{lstlisting}
+
+
+Each of these functions has a local variable - {\tt LongBowRunner *testRunner} - which may be used to manipulate the clipboard (as an example). The Text Fixtures and Test Cases launched by the Test Runner will have access to this variable as well as their own local variable. Thus a Test Fixture will have access to the {\tt testRunner} that is passed to it as well as its own {\tt LongBowFixture *testFixture} and a Test Case will have access to {\tt testRunner, testFixture} and its own {\tt LongBowCase *testCase}.
+
+\subsubsection{Test Fixtures}
+
+
+A Test Fixture is a subcomponent which has the same structure as a Test Runner. The following code adds Test Fixture to a Test Runner:
+
+\begin{lstlisting}
+LONGBOW_TEST_RUNNER(myRunner)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+\end{lstlisting}
+
+
+Like the Test Runner, it is responsible for setting up and tearing down state needed by the Test Cases.
+
+\begin{lstlisting}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, myTest);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+\end{lstlisting}
+
+\subsubsection{Test Cases}
+Test Cases are the leaf nodes of the testing tree. Each Test Case tests one aspect of the C module.
+
+\paragraph {Handling Test Case state safely}
+
+Every Test Case has access to a private \"clipboard\" that contains data shared between the Test Case and the set up and teardown functions of its encapsulating Test Fixture. This shared state is used to provide specific environment or initialized variables for the test and for the test to communicate specialized information to the teardown function.
+
+For example, a Test Case which is expected to fail as the result of testing a failure condition might exit without releasing resources which are left in an unsafe state. As multiple tests may be run in one process, it is important to clean these up before launching the next test.
+
+The following example demonstrates the clipboard mechanism:
+\begin{itemize}
+\item{The Test Fixture setup function allocates the necessary resources and puts references to them into the clipboard.}
+\item{The Test Case gets these references, uses them, and fails.}
+\item{The Test Fixture tear-down function obtains the resources from the clipboard and deallocates them.}
+\end{itemize}
+
+\subsubsection {Test Runner Example}
+\noindent The following is an example of a test file :
+
+\begin{lstlisting}
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+LONGBOW_TEST_RUNNER(testClipboard)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(testClipboard)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(testClipboard)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, testClipboard);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ char *testData = strdup("Hello World");
+ longBowTest Case_SetClipBoardData(testCase, testData, free);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, testClipboard)
+{
+ char *testData = longBowTest Case_GetClipBoardData(testCase);
+ printf("Shared state '%s'\n", testData);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(testClipboard);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTest Runner_Destroy(&testRunner);
+ exit(exitStatus);
+}
+\end{lstlisting}
+
+\subsubsection {Testing for Successful Failure}
+Testing for success is straightforward but we also may have to test that something fails when it is supposed to.
+This section describes how to test for an expected non-success result.
+
+To compose a Test Case that expects a result other than success, use the {\tt LONGBOW\_TEST\_CASE\_EXPECTS} function which takes the expected event as a parameter and completes. The example below shows the capture of a successful segmentation fault.
+
+
+\begin{lstlisting}
+#include <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(LongBow)
+{
+ LONGBOW_RUN_TEST_FIXTURE(MyFixture);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(LongBow)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(LongBow)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(MyFixture)
+{
+ LONGBOW_RUN_TEST_CASE(MyFixture, alwaysSEGV);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(MyFixture)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(MyFixture)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(MyFixture, alwaysSEGV, .event = &LongBowEventSIGSEGV)
+{
+ int *p = 0;
+ int i = *p;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(LongBow);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner, NULL);
+ longBowTest Runner_Destroy(&testRunner);
+
+ exit(status);
+}
+
+\end{lstlisting}
+
+\subsection{Running tests}
+
+The overall process for writing and running your tests:
+\begin{itemize}
+\item Write a Test Runner file for every .c file that completely tests all of the code container in the .c file. This filename should be "test\_" prepended to the name of the file you are testing.
+\item Compile the Test Runner file with one of:
+\begin {itemize}
+\item -llongbow -llongbow-ansiterm
+\item -llongbow -llongbow-textplain
+\end{itemize}
+\item Execute the Test Runner.
+\end{itemize}
+
+
+\subsection{Examples }
+
+Here is an example of a C source file and its associated Test file. Tutorial.c is a small C program which simply provides an uninteresting but useful exemplar of the test framework.
+
+
+\noindent \textbf{Tutorial.c}
+
+\begin{lstlisting}
+#include <unistd.h>
+#include <stdbool.h>
+#include <signal.h>
+
+static bool
+_privateFunction()
+{
+ return true;
+}
+
+bool
+alwaysSucceed()
+{
+ return _privateFunction();
+}
+
+bool
+alwaysFail()
+{
+ return false;
+}
+
+bool
+blowUp()
+{
+ char *p = 0;
+ *p = 0;
+
+ return true;
+}
+
+\end{lstlisting}
+
+The following code is the test file for the Tutorial.c. Note that the file name is simply the C source file name with "test\_" prepended. In this example, the Test Runner divides the Test Cases into two Test Fixtures: one to focus on the Static functions and one to focus on the Global functions.
+
+\noindent \textbf{test\_Tutorial.c}
+\begin{lstlisting}
+
+#include "tutorial.c"
+
+#include <LongBow/unit-test.h>
+
+
+LONGBOW_TEST_RUNNER(myTutorialTest)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, alwaysSucceed);
+ LONGBOW_RUN_TEST_CASE(Global, alwaysFail);
+ LONGBOW_RUN_TEST_CASE(Global, blowUp);
+
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, alwaysSucceed)
+{
+ bool result = alwaysSucceed();
+
+ assertTrue(result, "This test must always succeed.");
+}
+
+LONGBOW_TEST_CASE(Global, alwaysFail)
+{
+ bool result = alwaysFail();
+
+ assertTrue(result, "This test will fail.");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, blowUp, .event = &LongBowEventSIGSEGV)
+{
+ blowUp();
+
+ assertTrue(false, "This will not be executed");
+}
+
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, _privateFunction);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Static, _privateFunction)
+{
+ bool result = _privateFunction();
+
+ assertTrue(result, "This test must always succeed.");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(myTutorialTest);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+
+ longBowTest Runner_Destroy(&testRunner);
+ exit(status);
+}
+
+\end{lstlisting}
+
+\section {Compiling and Compiler Support}
+LongBow consolidates a variety of compile-time options that you include in your code.
+
+For example, the C99 standard defines the pragma operator and various compilers support this in various ways.
+
+\section{The LongBow Reporter}
+The Longbow reporter offers a more user-friendly option for viewing the output of the running tests. In addition to linking with the primary LongBow library ({\tt liblongbow.a}), you also need to link with one of the following reporting libraries to control presentation of the test output.
+\begin{itemize}
+\item {\bf liblongbow-ansiterm.a} This option produces output that is color coded to indicate the degree of success: green for a successful test; yellow for warnings; and red for failure.
+\item {\bf liblongbow-plaintext.a} This option produces plain text output.
+\item {\bf liblongbow-json.a} This option is in development and will produce output in JSON format.
+\end{itemize}
+
+
+
+\section {Appendices}
+\subsection {Function Documentation}
+The following modules are included in LongBow:
+\begin {itemize}
+\item \textbf{Runtime:} LongBow functions and macros for runtime.
+\item \textbf{Testing:} LongBow functions and macros for writing tests.
+\item \textbf{Internals:} LongBow functions and macros used internally.
+\item \textbf{Reporting:} LongBow functions and definitions for writing report libraries.
+\item \textbf{Performance testing:} LongBow functions and definitions for writing performance tests.
+\end{itemize}
+
+\paragraph {Runtime}
+LongBow runtime support consists primarily of assertions and traps. Developers insert assertions to insist that certain conditions are true before permitting the program to continue. If the assertion fails, the program is abnormally terminated. It uses the following files:
+
+\begin{itemize}
+\item {\bf assertions.h:} Runtime and Test Assertions.
+ \item {\bf longBow\_EventType.h:} LongBow Events and Support.
+ \item {\bf longBow\_Runtime.h:} The LongBow Runtime support.
+ \item {\bf runtime.h:} LongBow Runtime Support.
+ \item {\bf traps.h:} Runtime and Test Traps.
+\end{itemize}
+
+
+\paragraph {Testing}
+LongBow testing support consists of macros and ancillary functions to implement an xUnit style of writing and running tests. Test writers create a LONGBOW\_TEST\_RUNNER function which invokes one or more LONGBOW\_TEST\_FIXTURE functions, each of which invoke a specific LONGBOW\_TEST\_CASE. It uses the following files:
+
+\begin{itemize}
+\item {\bf longBow\_EventType.h:} LongBow Events and Support.
+ \item {\bf longBow\_Main.h:} A main() function to run one or more LongBow Test Runners.
+ \item {\bf longBow\_OpenFile.h:} LongBow support for files and file descriptors.
+ \item {\bf longBow\_Runner.h:} LongBow Test Runner Support.
+ \item {\bf longBow\_Status.h} A simple status representation for a LongBow Test Case.
+ \item {\bf longBow\_Test CaseClipBoard.h:} LongBow Clipboard shared between the setup, test case, and teardown.
+ \item {\bf longBow\_UnitTesting.h} Unit Testing Support. .
+ \item {\bf testing.h:} LongBow testing functionality.
+ \item {\bf unit-test.h} LongBow Unit Test Support.
+\end{itemize}
+
+\paragraph {Internals}
+LongBow functions and macros used internally.
+It uses the following files:
+
+\begin{itemize}
+ \item {\bf longBow\_ArrayList.h} A simple, list implementation using a dynamic array.
+ \item {\bf longBow\_Backtrace.h} Support for Stack Traces.
+ \item {\bf longBow\_Configuration.h} Support for LongBow Configuration.
+ \item {\bf longBow\_Debugging.h} Support for LongBow and Application Debugging.
+ \item {\bf longBow\_Event.h} LongBow Event Support.
+ \item {\bf longBow\_EventType.h} LongBow Events and Support.
+ \item {\bf longBow\_Fixture.h} Manage the execution of Test Cases.
+ \item {\bf longBow\_Location.h} LongBow Source File Location.
+ \item {\bf longBow\_Test Case.h} The interface and supporting functionality of a LongBow Test Case.
+ \item {\bf longBow\_Test CaseResult.h} LongBow Test Case Results.
+\end{itemize}
+
+
+ \paragraph {Reporting}
+LongBow functions and definitions for writing report libraries.
+It uses the following header files:
+
+\begin{itemize}
+ \item {\bf longBow\_ReportANSITerminal\_Runtime.h} ANSI Terminal Reporting.
+\item {\bf longBow\_Report\_Runtime.h} The LongBow Runtime Report Generator.
+\item {\bf longBow\_Report\_Testing.h} The LongBow Test Report Generator.
+\end{itemize}
+
+
+ \paragraph {Performance Testing}
+Using LongBow for performance tests.
+
+
+\end{document} \ No newline at end of file
diff --git a/longbow/documentation/LaTeX Documentation/old/SelfArx2.cls b/longbow/documentation/LaTeX Documentation/old/SelfArx2.cls
new file mode 100755
index 00000000..704a5e6e
--- /dev/null
+++ b/longbow/documentation/LaTeX Documentation/old/SelfArx2.cls
@@ -0,0 +1,191 @@
+% ---------------------------------------------------------------------
+% Conference proceedings and article templates for
+% personal open-archiving activities
+% September 2012
+%
+% 4/16/14 Marc Mosko - changed \arabic{section} to just {\thesection} so appendix prints as "A", etc.
+% 4/16/14 Marc Mosko - Changes how package xcolor is loaded so it has the "table" option
+%
+% ---------------------------------------------------------------------
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{SelfArx}[25/01/2012, v1.0]
+\RequirePackage{ifthen}
+\RequirePackage{calc}
+\AtEndOfClass{\RequirePackage{microtype}}
+\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}
+\ProcessOptions*
+\LoadClass{article}
+
+\RequirePackage{times} % Loads the Times-Roman Fonts
+\RequirePackage{mathptmx} % Loads the Times-Roman Math Fonts
+\RequirePackage{ifpdf} % Needed to pick between latex and pdflatex
+
+% ---------------------------------------------------------------------
+\RequirePackage[utf8]{inputenc}
+\RequirePackage{amsmath,amsfonts,amssymb}
+\RequirePackage{graphicx}
+\RequirePackage[table]{xcolor}
+\RequirePackage[english]{babel}
+\RequirePackage{booktabs}
+% ---------------------------------------------------------------------
+
+%%%%% for abstract+authors frames
+
+
+% ---------------------------------------------------------------------
+% margins
+\RequirePackage[left=2cm,%
+ right=2cm,%
+ top=2.25cm,%
+ bottom=2.25cm,%
+ headheight=11pt,%
+ letterpaper]{geometry}%
+\RequirePackage[labelfont={bf,sf},%
+ labelsep=period,%
+ justification=raggedright]{caption}
+% ---------------------------------------------------------------------
+\RequirePackage{fancyhdr} % Needed to define custom headers/footers
+\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{color1}\large\sffamily\bfseries}
+ {}
+ {0em}
+ {\colorbox{color2!10}{\parbox{\dimexpr\linewidth-2\fboxsep\relax}{\centering{\thesection}. #1}}}
+ []
+\titleformat{name=\section,numberless}
+ {\color{color1}\large\sffamily\bfseries}
+ {}
+ {0em}
+ {\colorbox{color2!10}{\parbox{\dimexpr\linewidth-2\fboxsep\relax}{\centering#1}}}
+ []
+\titleformat{\subsection}
+ {\color{color1}\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
+\usepackage{titletoc}
+\contentsmargin{0cm}
+\titlecontents{section}[\tocsep]
+ {\addvspace{4pt}\small\bfseries\sffamily}
+ {\contentslabel[\thecontentslabel]{\tocsep}}
+ {}
+ {\hfill\thecontentspage}
+ []
+\titlecontents{subsection}[\tocsep]
+ {\addvspace{2pt}\small\sffamily}
+ {\contentslabel[\thecontentslabel]{\tocsep}}
+ {}
+ {\ \titlerule*[.5pc]{.}\ \thecontentspage}
+ []
+\titlecontents*{subsubsection}[\tocsep]
+ {\footnotesize\sffamily}
+ {}
+ {}
+ {}
+ [\ \textbullet\ ]
+% ---------------------------------------------------------------------
+% Get the 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}}
+% ---------------------------------------------------------------------
+\RequirePackage{enumitem}
+%\setlist{nolistsep} % Uncomment to remove spacing between items in lists (enumerate, itemize)
+% ---------------------------------------------------------------------
+% Remove brackets from numbering in List of References
+\renewcommand{\@biblabel}[1]{\bfseries\color{color1}\textsuperscript{[#1]}}
+%\setlength{\bibitemsep}{0cm}
+% ---------------------------------------------------------------------
+\newcommand{\PaperTitle}[1]{\def\@PaperTitle{#1}}
+\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}}
+% ---------------------------------------------------------------------
+\renewcommand{\@maketitle}{%
+\twocolumn[{%
+\thispagestyle{empty}%
+\vskip-36pt%
+{\raggedleft\small\sffamily\bfseries\@JournalInfo\\\@Archive\par}%
+\vskip20pt%
+{\raggedright\color{color1}\sffamily\bfseries\fontsize{20}{25}\selectfont \@PaperTitle\par}%
+\vskip10pt
+{\raggedright\color{color1}\sffamily\fontsize{12}{16}\selectfont \@Authors\par}
+\vskip18pt%
+\fcolorbox{color1}{white}{%
+\parbox{\textwidth-2\fboxsep-2\fboxrule}{\centering%
+\colorbox{color2!10}{%
+\parbox{\textwidth-3.5\fboxsep-3.5\fboxrule}{%
+\ifx\@Keywords\@empty
+\sffamily\small\textbf{\abstractname}\\\@Abstract
+\else
+\sffamily\small\textbf{\abstractname}\\\@Abstract\\[5pt]%
+\textbf{\keywordname}\\\@Keywords%
+\fi
+}%
+}%
+\vskip5pt%
+\begingroup%
+\raggedright\sffamily\small%
+\footnotesize\@affiliation\par%
+\endgroup%%
+}%
+}%
+\vskip25pt%
+}]%
+}%
+% ---------------------------------------------------------------------
+\let\oldbibliography\thebibliography
+\renewcommand{\thebibliography}[1]{%
+\addcontentsline{toc}{section}{\hspace*{-\tocsep}\refname}%
+\oldbibliography{#1}%
+\setlength\itemsep{0pt}%
+} \ No newline at end of file
diff --git a/longbow/documentation/LaTeX Documentation/parc_black_solid.png b/longbow/documentation/LaTeX Documentation/parc_black_solid.png
new file mode 100644
index 00000000..6abcf2f4
--- /dev/null
+++ b/longbow/documentation/LaTeX Documentation/parc_black_solid.png
Binary files differ
diff --git a/longbow/documentation/LongBow.pages/Index.zip b/longbow/documentation/LongBow.pages/Index.zip
new file mode 100644
index 00000000..71366536
--- /dev/null
+++ b/longbow/documentation/LongBow.pages/Index.zip
Binary files differ
diff --git a/longbow/documentation/LongBow.pages/Metadata/BuildVersionHistory.plist b/longbow/documentation/LongBow.pages/Metadata/BuildVersionHistory.plist
new file mode 100644
index 00000000..e4466590
--- /dev/null
+++ b/longbow/documentation/LongBow.pages/Metadata/BuildVersionHistory.plist
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<array>
+ <string>pages-trunk-20080703_5</string>
+ <string>pages-trunk-20080707_3</string>
+ <string>pages-trunk-20080904_1</string>
+ <string>local build-Nov 15 2011</string>
+ <string>local build-Oct 16 2012</string>
+ <string>local build-Nov 15 2011</string>
+ <string>local build-Oct 16 2012</string>
+ <string>M5.0-1465-1</string>
+</array>
+</plist>
diff --git a/longbow/documentation/LongBow.pages/Metadata/DocumentIdentifier b/longbow/documentation/LongBow.pages/Metadata/DocumentIdentifier
new file mode 100644
index 00000000..e1ab6f9d
--- /dev/null
+++ b/longbow/documentation/LongBow.pages/Metadata/DocumentIdentifier
@@ -0,0 +1 @@
+9F57C025-E7BF-4979-A02B-BE3E828928DC \ No newline at end of file
diff --git a/longbow/documentation/LongBow.pages/Metadata/Properties.plist b/longbow/documentation/LongBow.pages/Metadata/Properties.plist
new file mode 100644
index 00000000..8587d44e
--- /dev/null
+++ b/longbow/documentation/LongBow.pages/Metadata/Properties.plist
Binary files differ
diff --git a/longbow/documentation/LongBow.pages/preview-micro.jpg b/longbow/documentation/LongBow.pages/preview-micro.jpg
new file mode 100644
index 00000000..51318b08
--- /dev/null
+++ b/longbow/documentation/LongBow.pages/preview-micro.jpg
Binary files differ
diff --git a/longbow/documentation/LongBow.pages/preview-web.jpg b/longbow/documentation/LongBow.pages/preview-web.jpg
new file mode 100644
index 00000000..3e0f39da
--- /dev/null
+++ b/longbow/documentation/LongBow.pages/preview-web.jpg
Binary files differ
diff --git a/longbow/documentation/LongBow.pages/preview.jpg b/longbow/documentation/LongBow.pages/preview.jpg
new file mode 100644
index 00000000..54d8ec23
--- /dev/null
+++ b/longbow/documentation/LongBow.pages/preview.jpg
Binary files differ
diff --git a/longbow/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css b/longbow/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css
new file mode 100644
index 00000000..c4cadf15
--- /dev/null
+++ b/longbow/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/longbow/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css.map b/longbow/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.css.map
new file mode 100644
index 00000000..016a8dab
--- /dev/null
+++ b/longbow/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/longbow/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.min.css b/longbow/documentation/doxygen-extras/bootstrap/css/bootstrap-theme.min.css
new file mode 100644
index 00000000..4c3e7bad
--- /dev/null
+++ b/longbow/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/longbow/documentation/doxygen-extras/bootstrap/css/bootstrap.css b/longbow/documentation/doxygen-extras/bootstrap/css/bootstrap.css
new file mode 100644
index 00000000..c6f3d210
--- /dev/null
+++ b/longbow/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/longbow/documentation/doxygen-extras/bootstrap/css/bootstrap.css.map b/longbow/documentation/doxygen-extras/bootstrap/css/bootstrap.css.map
new file mode 100644
index 00000000..a02f6ba0
--- /dev/null
+++ b/longbow/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/longbow/documentation/doxygen-extras/bootstrap/css/bootstrap.min.css b/longbow/documentation/doxygen-extras/bootstrap/css/bootstrap.min.css
new file mode 100644
index 00000000..b6fe4e0f
--- /dev/null
+++ b/longbow/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/longbow/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.eot b/longbow/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 00000000..4a4ca865
--- /dev/null
+++ b/longbow/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.eot
Binary files differ
diff --git a/longbow/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.svg b/longbow/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 00000000..25691af8
--- /dev/null
+++ b/longbow/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/longbow/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.ttf b/longbow/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 00000000..67fa00bf
--- /dev/null
+++ b/longbow/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.ttf
Binary files differ
diff --git a/longbow/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.woff b/longbow/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 00000000..8c54182a
--- /dev/null
+++ b/longbow/documentation/doxygen-extras/bootstrap/fonts/glyphicons-halflings-regular.woff
Binary files differ
diff --git a/longbow/documentation/doxygen-extras/bootstrap/js/bootstrap.js b/longbow/documentation/doxygen-extras/bootstrap/js/bootstrap.js
new file mode 100644
index 00000000..b6ac8d99
--- /dev/null
+++ b/longbow/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/longbow/documentation/doxygen-extras/bootstrap/js/bootstrap.min.js b/longbow/documentation/doxygen-extras/bootstrap/js/bootstrap.min.js
new file mode 100644
index 00000000..d8398659
--- /dev/null
+++ b/longbow/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/longbow/documentation/doxygen-extras/bootstrap/js/npm.js b/longbow/documentation/doxygen-extras/bootstrap/js/npm.js
new file mode 100644
index 00000000..bf6aa806
--- /dev/null
+++ b/longbow/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/longbow/documentation/doxygen-extras/customdoxygen.css b/longbow/documentation/doxygen-extras/customdoxygen.css
new file mode 100644
index 00000000..8560f848
--- /dev/null
+++ b/longbow/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/longbow/documentation/doxygen-extras/doxy-boot.js b/longbow/documentation/doxygen-extras/doxy-boot.js
new file mode 100644
index 00000000..5ee5fa37
--- /dev/null
+++ b/longbow/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/longbow/documentation/doxygen-extras/doxygen-bootstrap.js b/longbow/documentation/doxygen-extras/doxygen-bootstrap.js
new file mode 100755
index 00000000..2ddb6474
--- /dev/null
+++ b/longbow/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/longbow/documentation/doxygen-extras/footer.html b/longbow/documentation/doxygen-extras/footer.html
new file mode 100755
index 00000000..9ed5f12a
--- /dev/null
+++ b/longbow/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=11081165;
+var sc_invisible=0;
+var sc_security="5698c63a";
+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/11081165/0/5698c63a/0/" alt="shopify site analytics" />
+</a></div></noscript>
+ </div>
+<!-- End of StatCounter Code for Default Guide -->
+</body>
+</html>
diff --git a/longbow/documentation/doxygen-extras/header.html b/longbow/documentation/doxygen-extras/header.html
new file mode 100755
index 00000000..e6302c57
--- /dev/null
+++ b/longbow/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="logo_fdio.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/longbow/documentation/doxygen-extras/masthead.css b/longbow/documentation/doxygen-extras/masthead.css
new file mode 100644
index 00000000..7827e079
--- /dev/null
+++ b/longbow/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/longbow/documentation/examples/testAssertion.c b/longbow/documentation/examples/testAssertion.c
new file mode 100755
index 00000000..eb60db91
--- /dev/null
+++ b/longbow/documentation/examples/testAssertion.c
@@ -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.
+ */
+
+#include "../runtime.h"
+
+int
+main(int argc, char *argv[])
+{
+ assertTrue(0, "Force this assertion.");
+}
diff --git a/longbow/documentation/images/logo_fdio.png b/longbow/documentation/images/logo_fdio.png
new file mode 100644
index 00000000..ddfef2c7
--- /dev/null
+++ b/longbow/documentation/images/logo_fdio.png
Binary files differ
diff --git a/longbow/documentation/images/noise_gradient.jpg b/longbow/documentation/images/noise_gradient.jpg
new file mode 100644
index 00000000..30ecc02c
--- /dev/null
+++ b/longbow/documentation/images/noise_gradient.jpg
Binary files differ
diff --git a/longbow/documentation/imported-stylesheet.css b/longbow/documentation/imported-stylesheet.css
new file mode 100644
index 00000000..97541013
--- /dev/null
+++ b/longbow/documentation/imported-stylesheet.css
@@ -0,0 +1 @@
+@import "../assets/css/longbow-doxygen.css";
diff --git a/longbow/documentation/longbow-logo.gif b/longbow/documentation/longbow-logo.gif
new file mode 100644
index 00000000..ae4cd838
--- /dev/null
+++ b/longbow/documentation/longbow-logo.gif
Binary files differ
diff --git a/longbow/documentation/longbow.conf b/longbow/documentation/longbow.conf
new file mode 100644
index 00000000..0366e5a5
--- /dev/null
+++ b/longbow/documentation/longbow.conf
@@ -0,0 +1,2382 @@
+# 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 = LongBow
+
+# 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 = "LongBow: Write Better C Programs"
+
+# 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 = longbow-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 = 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 = NO
+
+# 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 = YES
+
+# 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 = 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 = longbow.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 = ../src/LongBow ../src/python
+
+# 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 =
+
+# 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 = 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 = 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 = doxygen-extras/customdoxygen.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 = doxygen-extras/doxygen-bootstrap.js
+
+# 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 = 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 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 = YES
+
+# 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 = letter
+
+# 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 =
+
+# 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 = longbow.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.
+# 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/longbow/documentation/longbow.doxygen.in b/longbow/documentation/longbow.doxygen.in
new file mode 100644
index 00000000..bda93d29
--- /dev/null
+++ b/longbow/documentation/longbow.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 = LongBow
+
+# 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 = "LongBow: Write Better C Programs"
+
+# 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 =
+
+# 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 = 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 = longbow.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@/../src/LongBow
+# ../src/python
+
+# 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 = ../src/LongBow/test
+
+# 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/* \
+ *private*
+
+# 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/logo_fdio.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.LongBow
+
+# 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 =
+
+# 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 = longbow.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.
+# 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/longbow/documentation/longbow.gif b/longbow/documentation/longbow.gif
new file mode 100644
index 00000000..140bd01c
--- /dev/null
+++ b/longbow/documentation/longbow.gif
Binary files differ
diff --git a/longbow/documentation/stylesheet.css b/longbow/documentation/stylesheet.css
new file mode 100644
index 00000000..fb5cda7c
--- /dev/null
+++ b/longbow/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/longbow/scripts/build-package.sh b/longbow/scripts/build-package.sh
new file mode 100644
index 00000000..9bab45e5
--- /dev/null
+++ b/longbow/scripts/build-package.sh
@@ -0,0 +1,196 @@
+#!/bin/bash
+# basic build script example
+set -euxo pipefail
+IFS=$'\n\t'
+
+SCRIPT_PATH=$( cd "$(dirname "${BASH_SOURCE}")" ; pwd -P )
+APT_PATH=`which apt-get` || true
+apt_get=${APT_PATH:-"/usr/local/bin/apt-get"}
+
+BUILD_TOOLS_UBUNTU="build-essential doxygen"
+LIBSSL_LIBEVENT_UBUNTU="libevent-dev libssl-dev"
+DEPS_UBUNTU=""
+
+BUILD_TOOLS_GROUP_CENTOS="'Development Tools'"
+LIBSSL_LIBEVENT_CENTOS="libevent-devel openssl-devel"
+DEPS_CENTOS=""
+
+update_cmake_repo() {
+
+ cat /etc/resolv.conf
+ echo "nameserver 8.8.8.8" | sudo tee -a /etc/resolv.conf
+ cat /etc/resolv.conf
+
+ CMAKE_INSTALL_SCRIPT_URL="https://cmake.org/files/v3.8/cmake-3.8.0-Linux-x86_64.sh"
+ CMAKE_INSTALL_SCRIPT="/tmp/install_cmake.sh"
+ curl ${CMAKE_INSTALL_SCRIPT_URL} > ${CMAKE_INSTALL_SCRIPT}
+
+ sudo mkdir -p /opt/cmake
+ sudo bash ${CMAKE_INSTALL_SCRIPT} --skip-license --prefix=/opt/cmake
+ export PATH=/opt/cmake/bin:$PATH
+}
+
+# Parameters:
+# $1 = Distribution codename
+#
+update_qt_repo() {
+ DISTRIBUTION_CODENAME=$1
+
+ if [ "$DISTRIBUTION_CODENAME" != "trusty" ] && [ "$DISTRIBUTION_CODENAME" != "xenial" ]; then
+ echo "No valid distribution specified when calling 'update_qt_repo'. Exiting.."
+ exit -1
+ fi
+
+ sudo ${apt_get} install -y --allow-unauthenticated software-properties-common
+ sudo add-apt-repository --yes ppa:beineri/opt-qt571-$DISTRIBUTION_CODENAME
+
+ wget -q -O - http://archive.getdeb.net/getdeb-archive.key | sudo apt-key add -
+ sudo sh -c "echo 'deb http://archive.getdeb.net/ubuntu $DISTRIBUTION_CODENAME-getdeb apps' >> /etc/apt/sources.list.d/getdeb.list"
+
+ sudo ${apt_get} update
+}
+
+# Parameters:
+# $1 = Distribution id
+# $2 = Distribution codename
+#
+update_fdio_repo() {
+ DISTRIB_ID=$1
+ DISTRIB_CODENAME=$2
+
+ NEXUS_PROXY=${NEXUSPROXY:-"http://nexus.fd.io"}
+ REPO_CICN_URL=""
+ REPO_VPP_URL=""
+
+ if [ "$DISTRIB_ID" == "Ubuntu" ]; then
+
+ if [ "$DISTRIB_CODENAME" == "xenial" ]; then
+ REPO_VPP_URL="${NEXUS_PROXY}/content/repositories/fd.io.stable.1701.ubuntu.xenial.main/"
+ REPO=${REPO_NAME:-"master.ubuntu.xenial.main"}
+ REPO_CICN_URL="${NEXUS_PROXY}/content/repositories/fd.io.${REPO}"
+ elif [ "$DISTRIB_CODENAME" == "trusty" ]; then
+ REPO_VPP_URL="${NEXUS_PROXY}/content/repositories/fd.io.stable.1701.ubuntu.trusty.main/"
+ REPO=${REPO_NAME:-"master.ubuntu.trusty.main"}
+ REPO_CICN_URL="${NEXUS_PROXY}/content/repositories/fd.io.${REPO}"
+ else
+ echo "Distribution $DISTRIB_CODENAME is not supported"
+ exit -1
+ fi
+
+ echo "deb ${REPO_VPP_URL} ./" | sudo tee /etc/apt/sources.list.d/99fd.io.list
+ echo "deb ${REPO_CICN_URL} ./" | sudo tee /etc/apt/sources.list.d/99fd.io.master.list
+
+ elif [ "$DISTRIB_ID" == "CentOS" ]; then
+ REPO_VPP_URL="${NEXUS_PROXY}/content/repositories/fd.io.centos7/"
+ REPO=${REPO_NAME:-"master.centos7"}
+ REPO_CICN_URL="${NEXUS_PROXY}/content/repositories/fd.io.${REPO}"
+
+ sudo cat << EOF > fdio.repo
+[fdio-vpp-master]
+name=fd.io master branch latest merge
+baseurl=${REPO_VPP_URL}
+enabled=1
+gpgcheck=0
+
+[fdio-cicn-master]
+name=fd.io master branch latest merge
+baseurl=${REPO_CICN_URL}
+enabled=1
+gpgcheck=0
+EOF
+ sudo mv fdio.repo /etc/yum.repos.d/fdio.repo
+ else
+ echo "Distribution $DISTRIB_CODENAME is not supported"
+ exit -1
+ fi
+}
+
+setup() {
+
+ DISTRIB_ID=$1
+ DISTRIB_CODENAME=$2
+
+ update_cmake_repo
+ update_fdio_repo $DISTRIB_ID $DISTRIB_CODENAME
+
+ if [ "$DISTRIB_ID" == "Ubuntu" ]; then
+ sudo ${apt_get} update || true
+ fi
+}
+
+# Parameters:
+# $1 = Package name
+#
+build_package() {
+
+ PACKAGE_NAME=$1
+
+ ARCHITECTURE=`uname -m`
+
+ # Figure out what system we are running on
+ if [ -f /etc/lsb-release ];then
+
+ . /etc/lsb-release
+ DEB=ON
+ RPM=OFF
+
+ if [ "$ARCHITECTURE" == "x86_64" ]; then
+ ARCHITECTURE="amd64"
+ fi
+
+ elif [ -f /etc/redhat-release ];then
+
+ sudo yum install -y redhat-lsb
+ DISTRIB_ID=`lsb_release -si`
+ DISTRIB_RELEASE=`lsb_release -sr`
+ DISTRIB_CODENAME=`lsb_release -sc`
+ DISTRIB_DESCRIPTION=`lsb_release -sd`
+
+ DEB=OFF
+ RPM=ON
+ else
+ echo "ERROR: System configuration not recognized. Build failed"
+ exit -1
+ fi
+
+ echo ARCHITECTURE: $ARCHITECTURE
+ echo DISTRIB_ID: $DISTRIB_ID
+ echo DISTRIB_RELEASE: $DISTRIB_RELEASE
+ echo DISTRIB_CODENAME: $DISTRIB_CODENAME
+ echo DISTRIB_DESCRIPTION: $DISTRIB_DESCRIPTION
+
+ setup $DISTRIB_ID $DISTRIB_CODENAME
+
+ # Install package dependencies
+ if [ $DISTRIB_ID == "Ubuntu" ]; then
+ echo $BUILD_TOOLS_UBUNTU $DEPS_UBUNTU | xargs sudo ${apt_get} install -y --allow-unauthenticated
+ elif [ $DISTRIB_ID == "CentOS" ]; then
+ echo $BUILD_TOOLS_GROUP_CENTOS | xargs sudo yum groupinstall -y --nogpgcheck
+ echo $DEPS_CENTOS | xargs sudo yum install -y --nogpgcheck || true
+ fi
+
+ # do nothing but print the current slave hostname
+ hostname
+
+ # Make the package
+ mkdir -p $SCRIPT_PATH/../build && pushd $SCRIPT_PATH/../build
+
+ rm -rf *
+ cmake -DCMAKE_INSTALL_PREFIX=/usr -DRPM_PACKAGE=$RPM -DDEB_PACKAGE=$DEB -DDISTRIBUTION=$DISTRIB_CODENAME -DARCHITECTURE=$ARCHITECTURE ..
+ make package
+
+ find . -not -name '*.deb' -not -name '*.rpm' -print0 | xargs -0 rm -rf -- || true
+
+ popd
+
+ echo "*******************************************************************"
+ echo "* $PACKAGE_NAME BUILD SUCCESSFULLY COMPLETED"
+ echo "*******************************************************************"
+
+ exit 0
+}
+
+PACKAGE_NAME="LONGBOW"
+pushd $SCRIPT_PATH/..
+build_package $PACKAGE_NAME
+popd
diff --git a/longbow/scripts/version b/longbow/scripts/version
new file mode 100644
index 00000000..fd6c6187
--- /dev/null
+++ b/longbow/scripts/version
@@ -0,0 +1,57 @@
+#!/bin/bash
+
+path=$( cd "$(dirname "${BASH_SOURCE}")" ; pwd -P )
+version_prefix="Longbow-v"
+
+cd "$path"
+
+git rev-parse 2> /dev/null
+if [ $? == 0 ]; then
+ vstring=$(git describe --dirty --match "$version_prefix*" | sed "s/$version_prefix//")
+elif [ -f .version ]; then
+ vstring=$(cat .version)
+else
+ if [ -f ../rpm/*.gz ]; then
+ vstring=$(ls ../rpm/*.gz)
+ else
+ exit 1
+ fi
+fi
+
+TAG=$(echo ${vstring} | cut -d- -f1 | sed -e "s/$version_prefix//")
+ADD=$(echo ${vstring} | cut -s -d- -f2)
+
+git rev-parse 2> /dev/null
+if [ $? == 0 ]; then
+ CMT=$(git describe --dirty --match "$version_prefix*" | sed "s/$version_prefix//" | cut -s -d- -f3,4)
+else
+ CMT=$(echo ${vstring} | cut -s -d- -f3,4)
+fi
+CMTR=$(echo $CMT | sed 's/-/_/')
+
+if [ -n "${BUILD_NUMBER}" ]; then
+ BLD="~b${BUILD_NUMBER}"
+else
+ BLD="~b1"
+fi
+
+if [ "$1" = "rpm-version" ]; then
+ echo ${TAG}
+ exit
+fi
+
+if [ "$1" = "rpm-release" ]; then
+ [ -z "${ADD}" ] && echo release && exit
+ echo ${ADD}${CMTR:+~${CMTR}}${BLD}
+ exit
+fi
+
+ if [ -n "${ADD}" ]; then
+ if [ "$1" = "rpm-string" ]; then
+ echo ${TAG}-${ADD}${CMTR:+~${CMTR}}${BLD}
+ else
+ echo ${TAG}-${ADD}${CMT:+~${CMT}}${BLD}
+ fi
+ else
+ echo ${TAG}-release
+fi \ No newline at end of file
diff --git a/longbow/src/CMakeLists.txt b/longbow/src/CMakeLists.txt
new file mode 100644
index 00000000..7ed5ddfe
--- /dev/null
+++ b/longbow/src/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(LongBow)
+add_subdirectory(python)
diff --git a/longbow/src/LongBow/.gitignore b/longbow/src/LongBow/.gitignore
new file mode 100644
index 00000000..6d86de6e
--- /dev/null
+++ b/longbow/src/LongBow/.gitignore
@@ -0,0 +1,2 @@
+*.gcda
+*.gcno
diff --git a/longbow/src/LongBow/CMakeLists.txt b/longbow/src/LongBow/CMakeLists.txt
new file mode 100644
index 00000000..f8054b8d
--- /dev/null
+++ b/longbow/src/LongBow/CMakeLists.txt
@@ -0,0 +1,191 @@
+# Define a few configuration variables that we want accessible in the software
+configure_file(
+ config.h.in
+ config.h
+)
+
+set(LONGBOW_REPORT_HEADER_FILES
+ Reporting/longBowReport_Testing.h
+ Reporting/longBowReport_Runtime.h
+ )
+
+set(LONGBOW_REPORT_BASE_SOURCE_FILES
+ Reporting/longBowReport_Runtime.c
+ Reporting/longBowReport_Testing.c
+ ${LONGBOW_REPORT_HEADER_FILES})
+
+source_group(report-base FILES ${LONGBOW_REPORT_BASE_SOURCE_FILES})
+
+set(LONGBOW_REPORT_ANSI_SOURCE_FILES
+ Reporting/ANSITerm/longBowReport_Runtime.c
+ Reporting/ANSITerm/longBowReport_Runtime.h
+ Reporting/ANSITerm/longBowReport_Testing.c
+ Reporting/ANSITerm/longBowReportANSITerminal_About.c
+ Reporting/ANSITerm/longBowReportANSITerminal_About.h)
+
+source_group(report-ansiterm FILES ${LONGBOW_REPORT_ANSI_SOURCE_FILES})
+
+
+if (ANDROID_API)
+ set(LONGBOW_REPORT_TEXT_RUNTIME_SOURCE_FILE Reporting/Android/longBowReport_Runtime.c)
+else()
+ set(LONGBOW_REPORT_TEXT_RUNTIME_SOURCE_FILE Reporting/TextPlain/longBowReport_Runtime.c)
+endif()
+
+ set(LONGBOW_REPORT_TEXT_SOURCE_FILES
+ ${LONGBOW_REPORT_TEXT_RUNTIME_SOURCE_FILE}
+ Reporting/TextPlain/longBowReport_Testing.c
+ Reporting/TextPlain/longBowReportTextPlain_About.c
+ Reporting/TextPlain/longBowReportTextPlain_About.h)
+
+source_group(report-textplain FILES ${LONGBOW_REPORT_TEXT_SOURCE_FILES})
+
+set(LONGBOW_CONFIG_SOURCE_FILES
+ command-line/liblongbow-config.c)
+
+source_group(longbow-config FILES ${LONGBOW_CONFIG_SOURCE_FILES})
+
+set(LIBLONGBOW_HEADER_FILES
+ stubs/execinfo.h
+ assertions.h
+ debugging.h
+ longBow_About.h
+ longBow_Backtrace.h
+ longBow_ClipBoard.h
+ longBow_Compiler.h
+ longBow_Config.h
+ longBow_Debug.h
+ longBow_Event.h
+ longBow_EventType.h
+ longBow_Location.h
+ longBow_Main.h
+ longBow_MeasureTime.h
+ longBow_Properties.h
+ longBow_Runtime.h
+ longBow_RuntimeResult.h
+ longBow_Status.h
+ longBow_SubProcess.h
+ longBow_TestCase.h
+ longBow_TestCaseClipBoard.h
+ longBow_TestCaseMetaData.h
+ longBow_TestFixture.h
+ longBow_TestFixtureConfig.h
+ longBow_TestRunner.h
+ longBow_UnitTest.h
+ longBow_UnitTesting.h
+ runtime.h
+ testing.h
+ tests.h
+ traps.h
+ unit-test.h
+ )
+
+set(LIBLONGBOW_SOURCE_FILES
+ private/longBow_ArrayList.h
+ private/longBow_Memory.h
+ private/longBow_OpenFile.h
+ private/longBow_String.h
+ private/longBow_ArrayList.c
+ private/longBow_Memory.c
+ private/longBow_OpenFile.c
+ private/longBow_String.c
+ longBow_About.c
+ longBow_Backtrace.c
+ longBow_ClipBoard.c
+ longBow_Config.c
+ longBow_Debug.c
+ longBow_Event.c
+ longBow_EventType.c
+ longBow_Location.c
+ longBow_Main.c
+ longBow_MeasureTime.c
+ longBow_Properties.c
+ longBow_Runtime.c
+ longBow_RuntimeResult.c
+ longBow_Status.c
+ longBow_SubProcess.c
+ longBow_TestCase.c
+ longBow_TestCaseClipBoard.c
+ longBow_TestCaseMetaData.c
+ longBow_TestFixture.c
+ longBow_TestFixtureConfig.c
+ longBow_TestRunner.c
+ longBow_UnitTesting.c
+ ${LIBLONGBOW_HEADER_FILES})
+
+source_group(longbow FILES ${LIBLONGBOW_SOURCE_FILES})
+
+if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang" OR COMPILE_FOR_IOS )
+ 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()
+
+if(COMPILE_FOR_IOS OR ANDROID_API)
+ add_library(longbow-ansiterm STATIC ${LONGBOW_REPORT_ANSI_SOURCE_FILES} ${LONGBOW_REPORT_BASE_SOURCE_FILES})
+
+ add_library(longbow-textplain STATIC ${LONGBOW_REPORT_TEXT_SOURCE_FILES} ${LONGBOW_REPORT_BASE_SOURCE_FILES})
+ add_library(longbow STATIC ${LIBLONGBOW_SOURCE_FILES})
+
+ set(longbowLibraries
+ longbow
+ longbow-ansiterm
+ longbow-textplain
+ )
+
+ foreach(lib ${longbowLibraries})
+ install(TARGETS ${lib} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
+ endforeach()
+else()
+ add_library(longbow-ansiterm STATIC ${LONGBOW_REPORT_ANSI_SOURCE_FILES} ${LONGBOW_REPORT_BASE_SOURCE_FILES})
+ add_library(longbow-ansiterm.shared SHARED ${LONGBOW_REPORT_ANSI_SOURCE_FILES} ${LONGBOW_REPORT_BASE_SOURCE_FILES})
+
+ set_target_properties(longbow-ansiterm.shared PROPERTIES
+ SOVERSION 1
+ VERSION 1.0
+ OUTPUT_NAME longbow-ansiterm)
+
+ add_library(longbow-textplain STATIC ${LONGBOW_REPORT_TEXT_SOURCE_FILES} ${LONGBOW_REPORT_BASE_SOURCE_FILES})
+ add_library(longbow-textplain.shared SHARED ${LONGBOW_REPORT_TEXT_SOURCE_FILES} ${LONGBOW_REPORT_BASE_SOURCE_FILES})
+
+ set_target_properties(longbow-textplain.shared PROPERTIES
+ SOVERSION 1
+ VERSION 1.0
+ OUTPUT_NAME longbow-textplain)
+
+ add_library(longbow STATIC ${LIBLONGBOW_SOURCE_FILES})
+ add_library(longbow.shared SHARED ${LIBLONGBOW_SOURCE_FILES})
+
+ set_target_properties(longbow.shared PROPERTIES
+ SOVERSION 1
+ VERSION 1.0
+ OUTPUT_NAME longbow)
+
+ add_executable(longbow-config ${LONGBOW_CONFIG_SOURCE_FILES})
+
+ set(longbowLibraries
+ longbow
+ longbow.shared
+ longbow-ansiterm
+ longbow-ansiterm.shared
+ longbow-textplain
+ longbow-textplain.shared
+ )
+
+ foreach(lib ${longbowLibraries})
+ install(TARGETS ${lib} COMPONENT library LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
+ endforeach()
+
+endif()
+
+install(FILES ${LIBLONGBOW_HEADER_FILES} DESTINATION include/LongBow COMPONENT headers)
+install(FILES ${LONGBOW_REPORT_HEADER_FILES} DESTINATION include/LongBow/Reporting COMPONENT headers)
+
+if(ANDROID_API)
+ message("############ Detected cross compile for ${CMAKE_SYSTEM_NAME}")
+ message("############ This build will not include doxygen, tools, or tests")
+elseif(COMPILE_FOR_IOS)
+ message("############ Detected cross compile for ${CMAKE_SYSTEM_NAME}")
+ message("############ This build will not include doxygen, tools, or tests")
+else()
+ add_subdirectory(test)
+endif()
diff --git a/longbow/src/LongBow/Groups.dox b/longbow/src/LongBow/Groups.dox
new file mode 100644
index 00000000..758f7abc
--- /dev/null
+++ b/longbow/src/LongBow/Groups.dox
@@ -0,0 +1,47 @@
+/**
+\mainpage LongBow
+
+Software testing, validation, and measurable quality metics are an important
+element in modern software development. LongBow is a software framework and
+facility for writing software using invariants, runtime validation,
+unit testing, and code analysis for the C programming language.
+
+LongBow is software to help you write better C programs. It provides:
+
+* A run-time assertion facility to establish strict rules on the state of your program.
+* A testing facility based on the xUnit testing model.
+* Compile-time assistance for writing code meant to be compiled by compilers with different features.
+
+LongBow can help you find and manage problems early, establish and maintain
+ confidence in the correctness of your code, make collaboration easier,
+facilitate future change, and improve overall design.
+
+LongBow allows you to take control and establish invariant pre- and
+post-conditions that detect inconsistencies and unexpected results in your
+programs in order to find bugs and design deficiencies in the code during
+development rather than waiting for your users and customers to find your bugs for you.
+
+
+@defgroup runtime Runtime
+@brief LongBow functions and macros for runtime, consisting primarily of assertions and traps.
+
+@defgroup testing Testing
+@brief LongBow functions and macros for writing tests.
+
+LongBow testing Macros and ancillary functions to implement an xUnit style of writing and running tests.
+Test writers create a `LONGBOW_TEST_RUNNER` function which, in turn,
+invokes one or more `LONGBOW_TEST_FIXTURE` functions,
+each of which invoke a specific `LONGBOW_TEST_CASE`.
+
+@defgroup internals Internals
+@brief LongBow functions and macros used internally.
+
+@defgroup reporting Reporting
+@brief LongBow functions and definitions for writing report libraries.
+
+@defgroup performance Performance testing
+@brief LongBow functions and definitions for writing performance tests.
+
+@example testAssertion.c
+*/
+
diff --git a/longbow/src/LongBow/Reporting/ANSITerm/longBowReportANSITerminal_About.c b/longbow/src/LongBow/Reporting/ANSITerm/longBowReportANSITerminal_About.c
new file mode 100644
index 00000000..e12c7b37
--- /dev/null
+++ b/longbow/src/LongBow/Reporting/ANSITerm/longBowReportANSITerminal_About.c
@@ -0,0 +1,44 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170214.46e2c73a 2017-02-14T20:35:31Z
+
+#include "longBowReportANSITerminal_About.h"
+
+const char *longBowReportANSITerminal_What = "@(#)" "LongBow ANSI Terminal Reporter " RELEASE_VERSION " 2017-02-14T21:39:44.348378"
+ "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates.";
+
+const char *
+longBowReportANSITerminalAbout_Name(void)
+{
+ return "LongBow ANSI Terminal Reporter";
+}
+
+const char *
+longBowReportANSITerminalAbout_Version(void)
+{
+ return RELEASE_VERSION;
+}
+
+const char *
+longBowReportANSITerminalAbout_About(void)
+{
+ return "LongBow ANSI Terminal Reporter "RELEASE_VERSION " 2017-02-14T21:39:44.348378" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+longBowReportANSITerminalAbout_MiniNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+longBowReportANSITerminalAbout_ShortNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+longBowReportANSITerminalAbout_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\n\n";
+}
+
diff --git a/longbow/src/LongBow/Reporting/ANSITerm/longBowReportANSITerminal_About.h b/longbow/src/LongBow/Reporting/ANSITerm/longBowReportANSITerminal_About.h
new file mode 100755
index 00000000..8dd3230c
--- /dev/null
+++ b/longbow/src/LongBow/Reporting/ANSITerm/longBowReportANSITerminal_About.h
@@ -0,0 +1,54 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170214.46e2c73a 2017-02-14T20:35:31Z
+
+#ifndef longBowReportANSITerminal_About_h
+#define longBowReportANSITerminal_About_h
+/**
+ * Embedded string containing information for the what(1) command.
+ *
+ */
+extern const char *longBowReportANSITerminal_What;
+
+/**
+ * Return the name as a C string.
+ *
+ * @return The name as a C string.
+ */
+const char *longBowReportANSITerminalAbout_Name(void);
+
+/**
+ * Return the version as a C string.
+ *
+ * @return The version as a C string.
+ */
+const char *longBowReportANSITerminalAbout_Version(void);
+
+/**
+ * Return the About text as a C string.
+ *
+ * @return The About text as a C string.
+ */
+const char *longBowReportANSITerminalAbout_About(void);
+
+/**
+ * Return the minimum copyright notice as a C string.
+ *
+ * @return The minimum copyright notice as a C string.
+ */
+const char *longBowReportANSITerminalAbout_MiniNotice(void);
+
+/**
+ * Return the short copyright notice as a C string.
+ *
+ * @return The short copyright notice as a C string.
+ */
+const char *longBowReportANSITerminalAbout_ShortNotice(void);
+
+/**
+ * Return the long copyright notice as a C string.
+ *
+ * @return The long copyright notice as a C string.
+ */
+const char *longBowReportANSITerminalAbout_LongNotice(void);
+
+#endif // longBowReportANSITerminal_About_h
diff --git a/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Runtime.c b/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Runtime.c
new file mode 100644
index 00000000..60ca4d42
--- /dev/null
+++ b/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Runtime.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <stdarg.h>
+#include <assert.h>
+
+#include <LongBow/Reporting/ANSITerm/longBowReport_Runtime.h>
+#include <LongBow/private/longBow_Memory.h>
+
+static const char *ansiRed = "\x1b[31m";
+static const char *ansiGreen = "\x1b[32m";
+static const char *ansiYellow = "\x1b[33m";
+static const char *ansiMagenta = "\x1b[35m";
+static const char *ansiReset = "\x1b[0m";
+
+static void
+_printGreen(void)
+{
+ printf("%s", ansiGreen);
+}
+
+static void
+_printYellow(void)
+{
+ printf("%s", ansiYellow);
+}
+
+static void
+_printMagenta(void)
+{
+ printf("%s", ansiMagenta);
+}
+
+static void
+_printReset(void)
+{
+ printf("%s", ansiReset);
+ fflush(stdout);
+}
+
+static void
+_longBowReportRuntime_RedPrintf(const char *format, va_list args)
+{
+ longBowReportRuntime_PrintRed();
+ vprintf(format, args);
+ _printReset();
+}
+
+static void
+_longBowReportRuntime_YellowPrintf(const char *format, va_list args)
+{
+ _printYellow();
+ vprintf(format, args);
+ _printReset();
+}
+
+void
+longBowReportRuntime_PrintRed(void)
+{
+ printf("%s", ansiRed);
+}
+
+void
+longBowReportRuntime_RedPrintf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ _longBowReportRuntime_RedPrintf(format, args);
+ va_end(args);
+}
+
+void
+longBowReportRuntime_GreenPrintf(const char *format, ...)
+{
+ _printGreen();
+ va_list args;
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+ _printReset();
+}
+
+void
+longBowReportRuntime_MagentaPrintf(const char *format, ...)
+{
+ _printMagenta();
+ va_list args;
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+ _printReset();
+}
+
+void
+longBowReportRuntime_YellowPrintf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+
+ _longBowReportRuntime_YellowPrintf(format, args);
+
+ va_end(args);
+}
+
+void
+longBowReportRuntime_ParseSuppress(LongBowReportConfig *result, const char *key)
+{
+ for (size_t i = 0; i < strlen(key); i++) {
+ if (*key == 'X') {
+ result->suppress_report.untested = 1;
+ } else if (*key == '.') {
+ result->suppress_report.succeeded = 1;
+ } else if (*key == 'S') {
+ result->suppress_report.skipped = 1;
+ } else if (*key == 'W') {
+ result->suppress_report.warned = 1;
+ } else if (*key == 's') {
+ result->suppress_report.setup_failed = 1;
+ } else if (*key == 't') {
+ result->suppress_report.teardown_failed = 1;
+ } else if (*key == 'w') {
+ result->suppress_report.teardown_warned = 1;
+ } else if (*key == 'F') {
+ result->suppress_report.failed = 1;
+ } else if (*key == 'T') {
+ result->suppress_report.stopped = 1;
+ } else if (*key == 'U') {
+ result->suppress_report.unimplemented = 1;
+ } else {
+ printf("Unknown suppression key '%c'\n", *key);
+ }
+ }
+}
+
+LongBowReportConfig *
+longBowReportRuntime_Create(int argc, char *argv[])
+{
+ static const char *prefix = "--report";
+ size_t prefixLength = strlen(prefix);
+
+ LongBowReportConfig *result = longBowMemory_Allocate(sizeof(LongBowReportConfig));
+
+ for (int i = 0; i < argc; i++) {
+ if (strncmp(prefix, argv[i], prefixLength) == 0) {
+ if (strcmp("--report-suppress", argv[i]) == 0) {
+ longBowReportRuntime_ParseSuppress(result, argv[i + 1]);
+ i++;
+ }
+ } else if (strcmp("--help", argv[i]) == 0) {
+ printf("Options for LongBow Report ANSI Terminal\n");
+ printf(" --report-suppress [STFU.XWstw] Suppress the display of specific reports.\n");
+ printf(" S - suppress the report of a skipped test.\n");
+ printf(" T - suppress the report of a stopped test.\n");
+ printf(" F - suppress the report of a failed test.\n");
+ printf(" U - suppress the report of an unimplemented test.\n");
+ printf(" . - suppress the report of a successful test.\n");
+ printf(" X - suppress the report of an untested test.\n");
+ printf(" W - suppress the report of a warned test.\n");
+ printf(" s - suppress the report of a setup failure.\n");
+ printf(" t - suppress the report of a tear-down failure.\n");
+ printf(" w - suppress the report of a tear-down warning.\n");
+ free(result);
+ return NULL;
+ }
+ }
+
+ return result;
+}
+
+void
+longBowReportRuntime_Destroy(LongBowReportConfig **reportPtr)
+{
+ longBowMemory_Deallocate((void **) reportPtr);
+}
+
+static void
+_EventPrint(const LongBowEvent *event)
+{
+ if (longBowEventType_IsSuppressAlert(longBowEvent_GetEventType(event)) == false) {
+ char *location = longBowLocation_ToString(longBowEvent_GetLocation(event));
+ printf("%s %s %s %s\r\n",
+ longBowEvent_GetName(event), location, longBowEvent_GetKind(event), longBowEvent_GetMessage(event));
+
+ if (longBowEventType_IsSuppressBacktrace(longBowEvent_GetEventType(event)) == false) {
+ char **strs = longBowEvent_CreateSymbolicCallstack(event);
+ if (strs != NULL) {
+ for (size_t i = 0; i < longBowEvent_GetCallStackLength(event); ++i) {
+ printf("%s\r\n", strs[i]);
+ }
+ free(strs);
+ }
+ }
+ fflush(stdout);
+ free(location);
+ }
+}
+
+void
+longBowReportRuntime_Event(const LongBowEvent *event)
+{
+ LongBowStatus status = longBowEventType_GetStatus(longBowEvent_GetEventType(event));
+ switch (status) {
+ case LongBowStatus_DONTCARE:
+ case LongBowStatus_UNTESTED:
+ break;
+
+ /* successful */
+ case LONGBOW_STATUS_SUCCEEDED:
+ // If this happens, there is an error in the encoding of the LongBowEventType.
+ longBowReportRuntime_PrintRed();
+ _EventPrint(event);
+ _printReset();
+ break;
+
+ case LongBowStatus_WARNED:
+ case LongBowStatus_TEARDOWN_WARNED:
+ case LONGBOW_STATUS_SKIPPED:
+ case LongBowStatus_UNIMPLEMENTED:
+ case LongBowStatus_IMPOTENT:
+ case LONGBOW_STATUS_MEMORYLEAK:
+ case LONGBOW_STATUS_SETUP_SKIPTESTS:
+ _printYellow();
+ _EventPrint(event);
+ _printReset();
+ break;
+
+ /* failure */
+ case LONGBOW_STATUS_FAILED:
+ case LongBowStatus_STOPPED:
+ case LONGBOW_STATUS_TEARDOWN_FAILED:
+ case LONGBOW_STATUS_SETUP_FAILED:
+ case LongBowStatus_SIGNALLED:
+ longBowReportRuntime_PrintRed();
+ _EventPrint(event);
+ _printReset();
+ break;
+
+ case LongBowStatus_LIMIT: // fall through
+ default:
+ _printYellow();
+ _EventPrint(event);
+ _printReset();
+ break;
+ }
+}
+
+void
+longBowReportRuntime_Message(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+}
+
+void
+longBowReportRuntime_Warning(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ longBowReportRuntime_YellowPrintf("WARNING ");
+ _longBowReportRuntime_YellowPrintf(format, args);
+ va_end(args);
+}
+
+void
+longBowReportRuntime_Error(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ longBowReportRuntime_RedPrintf("FAILURE ");
+ _longBowReportRuntime_RedPrintf(format, args);
+ va_end(args);
+}
diff --git a/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Runtime.h b/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Runtime.h
new file mode 100755
index 00000000..2e03f322
--- /dev/null
+++ b/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Runtime.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 ANSITerm/longBowReport_Runtime.h
+ * @ingroup reporting
+ * @brief ANSI Terminal Reporting
+ *
+ */
+#ifndef LongBow_longBowReport_ANSITerm_Runtime_h
+#define LongBow_longBowReport_ANSITerm_Runtime_h
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <LongBow/Reporting/longBowReport_Runtime.h>
+
+/**
+ * Begin printing in red.
+ *
+ */
+void longBowReportRuntime_PrintRed(void);
+
+/**
+ * Print the formatted string in red.
+ *
+ */
+void longBowReportRuntime_RedPrintf(const char *format, ...);
+
+/**
+ * Print the formatted string in green.
+ *
+ */
+void longBowReportRuntime_GreenPrintf(const char *format, ...);
+
+/**
+ * Print the formatted string in yellow.
+ *
+ */
+void longBowReportRuntime_YellowPrintf(const char *format, ...);
+
+/**
+ * Print the formatted string in magenta.
+ *
+ */
+void longBowReportRuntime_MagentaPrintf(const char *format, ...);
+
+/**
+ * Parse the given key and set the corresponding LongBowReportConfig to suppress reports.
+ *
+ * @param [in] config A valid LongBowReportConfig instance.
+ * @param [in] key A nul-terminated C string consisting of one or more of the characters, X.SWstwFTU
+ */
+void longBowReportRuntime_ParseSuppress(LongBowReportConfig *config, const char *key);
+#endif // LongBow_longBowReport_ANSITerm_Runtime_h
diff --git a/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Testing.c b/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Testing.c
new file mode 100644
index 00000000..d1952210
--- /dev/null
+++ b/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Testing.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 <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include <LongBow/Reporting/ANSITerm/longBowReport_Runtime.h>
+#include <LongBow/Reporting/longBowReport_Testing.h>
+#include <LongBow/private/longBow_String.h>
+
+static const LongBowTestRunner *
+_testRunnerSilent(const LongBowTestRunner *testRunner)
+{
+ LongBowStatus status = longBowTestRunner_GetStatus(testRunner);
+ if (longBowStatus_IsSuccessful(status)) {
+ longBowReportRuntime_GreenPrintf("%s %s\n", longBowTestRunner_GetName(testRunner), longBowStatus_ToString(status));
+ } else if (longBowStatus_IsSuccessful(status)) {
+ longBowReportRuntime_YellowPrintf("%s %s\n", longBowTestRunner_GetName(testRunner), longBowStatus_ToString(status));
+ } else {
+ longBowReportRuntime_RedPrintf("%s %s\n", longBowTestRunner_GetName(testRunner), longBowStatus_ToString(status));
+ }
+ return testRunner;
+}
+
+static const LongBowTestRunner *
+_testRunnerDetail(const LongBowTestRunner *testRunner)
+{
+ size_t nFixtures = longBowTestRunner_GetFixtureCount(testRunner);
+
+ printf("\n");
+ printf("%s: %zd fixture%s\n", longBowTestRunner_GetName(testRunner), nFixtures, (nFixtures == 1 ? "" : "s"));
+
+ for (size_t i = 0; i < nFixtures; i++) {
+ LongBowTestFixture *fixture = longBowTestRunner_GetFixture(testRunner, i);
+ longBowReportTesting_TestFixture(fixture);
+ }
+ return testRunner;
+}
+
+const LongBowTestRunner *
+longBowReportTesting_TestRunner(const LongBowTestRunner *testRunner)
+{
+ if (longBowConfig_GetBoolean(longBowTestRunner_GetConfiguration(testRunner), false, "silent")) {
+ return _testRunnerSilent(testRunner);
+ } else {
+ return _testRunnerDetail(testRunner);
+ }
+}
+
+static unsigned int
+_totalSucceeded(const LongBowTestFixtureSummary *summary)
+{
+ return summary->totalSucceeded + summary->totalWarned + summary->totalTearDownWarned;
+}
+
+static unsigned int
+_totalWarned(const LongBowTestFixtureSummary *summary)
+{
+ return summary->totalWarned + summary->totalTearDownWarned;
+}
+
+static unsigned int
+_totalFailed(const LongBowTestFixtureSummary *summary)
+{
+ return summary->totalFailed + summary->totalSignalled + summary->totalStopped + summary->totalTearDownFailed;
+}
+
+static unsigned int
+_totalIncomplete(const LongBowTestFixtureSummary *summary)
+{
+ return summary->totalSetupFailed + summary->totalSkipped + summary->totalUnimplemented;
+}
+
+static void
+_reportSummary(const LongBowTestFixture *testFixture)
+{
+ const LongBowTestFixtureSummary *summary = longBowTestFixture_GetSummary(testFixture);
+
+ char *fixtureString = longBowTestFixture_ToString(testFixture);
+
+ printf("%s: Ran %u test case%s.", fixtureString, summary->totalTested, summary->totalTested == 1 ? "" : "s");
+ free(fixtureString);
+
+ if (summary->totalTested > 0) {
+ printf(" %d%% (%d) succeeded", _totalSucceeded(summary) * 100 / summary->totalTested, _totalSucceeded(summary));
+
+ if (_totalWarned(summary) > 0) {
+ printf(" %d%% (%d) with warnings", _totalWarned(summary) * 100 / _totalSucceeded(summary), _totalWarned(summary));
+ }
+ if (_totalFailed(summary) != 0) {
+ printf(", %d%% (%d) failed", _totalFailed(summary) * 100 / summary->totalTested, _totalFailed(summary));
+ }
+ if (_totalIncomplete(summary) > 0) {
+ printf(", %d%% (%d) incomplete", _totalIncomplete(summary) * 100 / summary->totalTested, _totalIncomplete(summary));
+ }
+ }
+
+ printf("\n");
+}
+
+const LongBowTestFixture *
+longBowReportTesting_TestFixture(const LongBowTestFixture *testFixture)
+{
+ size_t nTestCases = longBowTestFixture_GetTestCaseCount(testFixture);
+
+ _reportSummary(testFixture);
+
+ for (size_t i = 0; i < nTestCases; i++) {
+ LongBowTestCase *testCase = longBowTestFixture_GetTestCase(testFixture, i);
+ longBowReportTesting_TestCase(testCase);
+ }
+ return testFixture;
+}
+
+const LongBowTestCase *
+longBowReportTesting_TestCase(const LongBowTestCase *testCase)
+{
+ LongBowRuntimeResult *testCaseResult = longBowTestCase_GetActualResult(testCase);
+
+ char *rusageString = longBowReportRuntime_RUsageToString(longBowRuntimeResult_GetRUsage(testCaseResult));
+ char *elapsedTimeString = longBowReportRuntime_TimevalToString(longBowRuntimeResult_GetElapsedTime(testCaseResult));
+ char *statusString = longBowStatus_ToString(longBowRuntimeResult_GetStatus(testCaseResult));
+ char *testCaseString = longBowTestCase_ToString(testCase);
+
+ LongBowString *str = longBowString_CreateFormat("%s %s %s %zd %s\n",
+ testCaseString,
+ elapsedTimeString,
+ rusageString,
+ longBowRuntimeResult_GetEventEvaluationCount(longBowTestCase_GetActualResult(testCase)),
+ statusString);
+ char *string = longBowString_ToString(str);
+
+ if (longBowTestCase_IsFailed(testCase)) {
+ longBowReportRuntime_RedPrintf("%s", string);
+ } else if (longBowTestCase_IsWarning(testCase)) {
+ longBowReportRuntime_YellowPrintf("%s", string);
+ } else if (longBowTestCase_IsIncomplete(testCase)) {
+ longBowReportRuntime_YellowPrintf("%s", string);
+ } else if (longBowTestCase_IsSuccessful(testCase)) {
+ longBowReportRuntime_GreenPrintf("%s", string);
+ } else {
+ longBowReportRuntime_RedPrintf("%s", string);
+ }
+
+ free(string);
+ free(testCaseString);
+ free(statusString);
+ free(elapsedTimeString);
+ free(rusageString);
+
+ return testCase;
+}
+
+void
+longBowReportTesting_DisplayTestCaseResult(const LongBowTestCase *testCase __attribute__((unused)))
+{
+}
+
+void
+longBowReportTesting_Trace(const char *restrict format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ char *message;
+ if (vasprintf(&message, format, ap) == -1) {
+ va_end(ap);
+ return;
+ }
+ va_end(ap);
+
+ longBowReportRuntime_MagentaPrintf("%s\n", message);
+ fflush(stdout);
+ free(message);
+}
diff --git a/longbow/src/LongBow/Reporting/Android/longBowReportAndroid_About.c b/longbow/src/LongBow/Reporting/Android/longBowReportAndroid_About.c
new file mode 100644
index 00000000..db31ce82
--- /dev/null
+++ b/longbow/src/LongBow/Reporting/Android/longBowReportAndroid_About.c
@@ -0,0 +1,44 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170214.46e2c73a 2017-02-14T20:35:31Z
+
+#include "longBowReportAndroid_About.h"
+
+const char *longBowReportAndroid_What = "@(#)" "LongBow Android Reporter " RELEASE_VERSION " 2017-02-14T21:38:07.631504"
+ "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates.";
+
+const char *
+longBowReportAndroidAbout_Name(void)
+{
+ return "LongBow Android Reporter";
+}
+
+const char *
+longBowReportAndroidAbout_Version(void)
+{
+ return RELEASE_VERSION;
+}
+
+const char *
+longBowReportAndroidAbout_About(void)
+{
+ return "LongBow Android Reporter "RELEASE_VERSION " 2017-02-14T21:38:07.631504" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+longBowReportAndroidAbout_MiniNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+longBowReportAndroidAbout_ShortNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+longBowReportAndroidAbout_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\n\n";
+}
+
diff --git a/longbow/src/LongBow/Reporting/Android/longBowReportAndroid_About.h b/longbow/src/LongBow/Reporting/Android/longBowReportAndroid_About.h
new file mode 100755
index 00000000..9a90f17e
--- /dev/null
+++ b/longbow/src/LongBow/Reporting/Android/longBowReportAndroid_About.h
@@ -0,0 +1,54 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170214.46e2c73a 2017-02-14T20:35:31Z
+
+#ifndef longBowReportAndroid_About_h
+#define longBowReportAndroid_About_h
+/**
+ * Embedded string containing information for the what(1) command.
+ *
+ */
+extern const char *longBowReportAndroid_What;
+
+/**
+ * Return the name as a C string.
+ *
+ * @return The name as a C string.
+ */
+const char *longBowReportAndroidAbout_Name(void);
+
+/**
+ * Return the version as a C string.
+ *
+ * @return The version as a C string.
+ */
+const char *longBowReportAndroidAbout_Version(void);
+
+/**
+ * Return the About text as a C string.
+ *
+ * @return The About text as a C string.
+ */
+const char *longBowReportAndroidAbout_About(void);
+
+/**
+ * Return the minimum copyright notice as a C string.
+ *
+ * @return The minimum copyright notice as a C string.
+ */
+const char *longBowReportAndroidAbout_MiniNotice(void);
+
+/**
+ * Return the short copyright notice as a C string.
+ *
+ * @return The short copyright notice as a C string.
+ */
+const char *longBowReportAndroidAbout_ShortNotice(void);
+
+/**
+ * Return the long copyright notice as a C string.
+ *
+ * @return The long copyright notice as a C string.
+ */
+const char *longBowReportAndroidAbout_LongNotice(void);
+
+#endif // longBowReportAndroid_About_h
diff --git a/longbow/src/LongBow/Reporting/Android/longBowReport_Runtime.c b/longbow/src/LongBow/Reporting/Android/longBowReport_Runtime.c
new file mode 100644
index 00000000..4bf13482
--- /dev/null
+++ b/longbow/src/LongBow/Reporting/Android/longBowReport_Runtime.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <assert.h>
+
+#include <LongBow/Reporting/longBowReport_Runtime.h>
+#include <LongBow/private/longBow_Memory.h>
+
+LongBowReportConfig *
+longBowReportRuntime_Create(int argc, char *argv[argc])
+{
+ LongBowReportConfig *result = longBowMemory_Allocate(sizeof(LongBowReportConfig));
+
+ return result;
+}
+
+void
+longBowReportRuntime_Destroy(LongBowReportConfig **reportPtr)
+{
+ longBowMemory_Deallocate((void **) reportPtr);
+}
+
+void
+longBowReportRuntime_Event(const LongBowEvent *event)
+{
+ if (longBowEventType_IsSuppressAlert(longBowEvent_GetEventType(event)) == false) {
+ char *location = longBowLocation_ToString(longBowEvent_GetLocation(event));
+ printf("%s %s %s %s\r\n",
+ longBowEvent_GetName(event), location, longBowEvent_GetKind(event), longBowEvent_GetMessage(event));
+
+ if (longBowEventType_IsSuppressBacktrace(longBowEvent_GetEventType(event)) == false) {
+ char **strs = longBowEvent_CreateSymbolicCallstack(event);
+ if (strs != NULL) {
+ for (size_t i = 0; i < longBowEvent_GetCallStackLength(event); ++i) {
+ fputs(strs[i], stdout);
+ fputs("\r\n", stdout);
+ }
+ free(strs);
+ }
+ }
+ fflush(stdout);
+
+ free(location);
+ }
+}
+
+void
+longBowReportRuntime_Message(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+}
+
+void
+longBowReportRuntime_Warning(const char *format, ...)
+{
+ printf("WARNING");
+
+ va_list args;
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+}
+
+void
+longBowReportRuntime_Error(const char *format, ...)
+{
+ printf("ERROR");
+ va_list args;
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+}
diff --git a/longbow/src/LongBow/Reporting/Android/longBowReport_Testing.c b/longbow/src/LongBow/Reporting/Android/longBowReport_Testing.c
new file mode 100755
index 00000000..dd3835e8
--- /dev/null
+++ b/longbow/src/LongBow/Reporting/Android/longBowReport_Testing.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 <assert.h>
+
+#ifdef __ANDROID__
+#include <android/log.h>
+#define printf(...) __android_log_print(ANDROID_LOG_DEBUG, "CCNx", __VA_ARGS__);
+#endif
+
+#include <LongBow/Reporting/longBowReport_Testing.h>
+#include <LongBow/private/longBow_String.h>
+
+static const LongBowTestRunner *
+_testRunnerSilent(const LongBowTestRunner *testRunner)
+{
+ LongBowStatus status = longBowTestRunner_GetStatus(testRunner);
+
+ printf("%s %s\n", longBowTestRunner_GetName(testRunner), longBowStatus_ToString(status));
+ return testRunner;
+}
+
+static const LongBowTestRunner *
+_testRunnerDetail(const LongBowTestRunner *testRunner)
+{
+ size_t nFixtures = longBowTestRunner_GetFixtureCount(testRunner);
+
+ printf("\r\n");
+ printf("%s: %zd fixture%s\r\n", longBowTestRunner_GetName(testRunner), nFixtures, (nFixtures == 1 ? "" : "s"));
+
+ for (size_t i = 0; i < nFixtures; i++) {
+ LongBowTestFixture *fixture = longBowTestRunner_GetFixture(testRunner, i);
+ longBowReportTesting_TestFixture(fixture);
+ }
+ return testRunner;
+}
+
+const LongBowTestRunner *
+longBowReportTesting_TestRunner(const LongBowTestRunner *testRunner)
+{
+ if (longBowConfig_GetBoolean(longBowTestRunner_GetConfiguration(testRunner), false, "silent")) {
+ return _testRunnerSilent(testRunner);
+ } else {
+ return _testRunnerDetail(testRunner);
+ }
+}
+
+static unsigned int
+_totalSucceeded(const LongBowTestFixtureSummary *summary)
+{
+ return summary->totalSucceeded + summary->totalWarned + summary->totalTearDownWarned;
+}
+
+static unsigned int
+_totalWarned(const LongBowTestFixtureSummary *summary)
+{
+ return summary->totalWarned + summary->totalTearDownWarned;
+}
+
+static unsigned int
+_totalFailed(const LongBowTestFixtureSummary *summary)
+{
+ return summary->totalFailed + summary->totalSignalled + summary->totalStopped + summary->totalTearDownFailed;
+}
+
+static unsigned int
+_totalIncomplete(const LongBowTestFixtureSummary *summary)
+{
+ return summary->totalSetupFailed + summary->totalSkipped + summary->totalUnimplemented;
+}
+
+static void
+_reportSummary(const LongBowTestFixture *testFixture)
+{
+ const LongBowTestFixtureSummary *summary = longBowTestFixture_GetSummary(testFixture);
+
+ char *fixtureString = longBowTestFixture_ToString(testFixture);
+
+ printf("%s: Ran %u test case%s.", fixtureString, summary->totalTested, summary->totalTested == 1 ? "" : "s");
+ free(fixtureString);
+
+ if (summary->totalTested > 0) {
+ printf(" %d%% (%d) succeeded", _totalSucceeded(summary) * 100 / summary->totalTested, _totalSucceeded(summary));
+
+ if (_totalWarned(summary) > 0) {
+ printf(" %d%% (%d) with warnings", _totalWarned(summary) * 100 / _totalSucceeded(summary), _totalWarned(summary));
+ }
+ if (_totalFailed(summary) != 0) {
+ printf(", %d%% (%d) failed", _totalFailed(summary) * 100 / summary->totalTested, _totalFailed(summary));
+ }
+ if (_totalIncomplete(summary) > 0) {
+ printf(", %d%% (%d) incomplete", _totalIncomplete(summary) * 100 / summary->totalTested, _totalIncomplete(summary));
+ }
+ }
+ printf("\n");
+}
+
+const LongBowTestFixture *
+longBowReportTesting_TestFixture(const LongBowTestFixture *testFixture)
+{
+ size_t nTestCases = longBowTestFixture_GetTestCaseCount(testFixture);
+
+ _reportSummary(testFixture);
+
+ for (size_t i = 0; i < nTestCases; i++) {
+ LongBowTestCase *testCase = longBowTestFixture_GetTestCase(testFixture, i);
+ longBowReportTesting_TestCase(testCase);
+ }
+ return testFixture;
+}
+
+const LongBowTestCase *
+longBowReportTesting_TestCase(const LongBowTestCase *testCase)
+{
+ LongBowRuntimeResult *testCaseResult = longBowTestCase_GetActualResult(testCase);
+
+ char *rusageString = longBowReportRuntime_RUsageToString(longBowRuntimeResult_GetRUsage(testCaseResult));
+
+ char *elapsedTimeString = longBowReportRuntime_TimevalToString(longBowRuntimeResult_GetElapsedTime(testCaseResult));
+
+ char *statusString = longBowStatus_ToString(longBowTestCase_GetActualResult(testCase)->status);
+ char *testCaseString = longBowTestCase_ToString(testCase);
+
+ LongBowString *string = longBowString_CreateFormat("%10s %s %s %zd %s\n",
+ testCaseString,
+ elapsedTimeString,
+ rusageString,
+ longBowRuntimeResult_GetEventEvaluationCount(longBowTestCase_GetActualResult(testCase)),
+ statusString);
+ longBowString_Write(string, stdout);
+ longBowString_Destroy(&string);
+
+ free(testCaseString);
+ free(statusString);
+ free(elapsedTimeString);
+ free(rusageString);
+
+ return testCase;
+}
+
+void
+longBowReportTesting_DisplayTestCaseResult(const LongBowTestCase *testCase)
+{
+ const LongBowRuntimeResult *testCaseResult = longBowTestCase_GetActualResult(testCase);
+
+ switch (testCaseResult->status) {
+ case LongBowStatus_UNTESTED: printf("X"); break;
+ case LONGBOW_STATUS_SUCCEEDED: printf("."); break;
+ case LONGBOW_STATUS_SKIPPED: printf("S"); break;
+ case LongBowStatus_WARNED: printf("W"); break;
+ case LONGBOW_STATUS_SETUP_FAILED: printf("s"); break;
+ case LONGBOW_STATUS_TEARDOWN_FAILED: printf("t"); break;
+ case LongBowStatus_TEARDOWN_WARNED: printf("w"); break;
+ case LONGBOW_STATUS_FAILED: printf("F"); break;
+ case LongBowStatus_STOPPED: printf("T"); break;
+ case LongBowStatus_UNIMPLEMENTED: printf("U"); break;
+ case LongBowStatus_IMPOTENT: printf("I"); break;
+ default:
+ if (testCaseResult->status >= LongBowStatus_SIGNALLED) {
+ printf("K");
+ } else {
+ printf("?");
+ }
+ }
+ fflush(stdout);
+}
+
+void
+longBowReportTesting_Trace(const char *restrict format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ char *message;
+ if (vasprintf(&message, format, ap) == -1) {
+ return;
+ }
+ va_end(ap);
+
+ printf("%s\n", message);
+ free(message);
+}
diff --git a/longbow/src/LongBow/Reporting/TextPlain/longBowReportTextPlain_About.c b/longbow/src/LongBow/Reporting/TextPlain/longBowReportTextPlain_About.c
new file mode 100644
index 00000000..aa385033
--- /dev/null
+++ b/longbow/src/LongBow/Reporting/TextPlain/longBowReportTextPlain_About.c
@@ -0,0 +1,44 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170214.46e2c73a 2017-02-14T20:35:31Z
+
+#include "longBowReportTextPlain_About.h"
+
+const char *longBowReportTextPlain_What = "@(#)" "LongBow Text Plain Reporter " RELEASE_VERSION " 2017-02-14T21:40:52.491677"
+ "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates.";
+
+const char *
+longBowReportTextPlainAbout_Name(void)
+{
+ return "LongBow Text Plain Reporter";
+}
+
+const char *
+longBowReportTextPlainAbout_Version(void)
+{
+ return RELEASE_VERSION;
+}
+
+const char *
+longBowReportTextPlainAbout_About(void)
+{
+ return "LongBow Text Plain Reporter "RELEASE_VERSION " 2017-02-14T21:40:52.491677" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+longBowReportTextPlainAbout_MiniNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+longBowReportTextPlainAbout_ShortNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+longBowReportTextPlainAbout_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\n\n";
+}
+
diff --git a/longbow/src/LongBow/Reporting/TextPlain/longBowReportTextPlain_About.h b/longbow/src/LongBow/Reporting/TextPlain/longBowReportTextPlain_About.h
new file mode 100755
index 00000000..08f69eb2
--- /dev/null
+++ b/longbow/src/LongBow/Reporting/TextPlain/longBowReportTextPlain_About.h
@@ -0,0 +1,54 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170214.46e2c73a 2017-02-14T20:35:31Z
+
+#ifndef longBowReportTextPlain_About_h
+#define longBowReportTextPlain_About_h
+/**
+ * Embedded string containing information for the what(1) command.
+ *
+ */
+extern const char *longBowReportTextPlain_What;
+
+/**
+ * Return the name as a C string.
+ *
+ * @return The name as a C string.
+ */
+const char *longBowReportTextPlainAbout_Name(void);
+
+/**
+ * Return the version as a C string.
+ *
+ * @return The version as a C string.
+ */
+const char *longBowReportTextPlainAbout_Version(void);
+
+/**
+ * Return the About text as a C string.
+ *
+ * @return The About text as a C string.
+ */
+const char *longBowReportTextPlainAbout_About(void);
+
+/**
+ * Return the minimum copyright notice as a C string.
+ *
+ * @return The minimum copyright notice as a C string.
+ */
+const char *longBowReportTextPlainAbout_MiniNotice(void);
+
+/**
+ * Return the short copyright notice as a C string.
+ *
+ * @return The short copyright notice as a C string.
+ */
+const char *longBowReportTextPlainAbout_ShortNotice(void);
+
+/**
+ * Return the long copyright notice as a C string.
+ *
+ * @return The long copyright notice as a C string.
+ */
+const char *longBowReportTextPlainAbout_LongNotice(void);
+
+#endif // longBowReportTextPlain_About_h
diff --git a/longbow/src/LongBow/Reporting/TextPlain/longBowReport_Runtime.c b/longbow/src/LongBow/Reporting/TextPlain/longBowReport_Runtime.c
new file mode 100755
index 00000000..b5cb4dfc
--- /dev/null
+++ b/longbow/src/LongBow/Reporting/TextPlain/longBowReport_Runtime.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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <assert.h>
+
+#include <LongBow/Reporting/longBowReport_Runtime.h>
+#include <LongBow/private/longBow_Memory.h>
+
+LongBowReportConfig *
+longBowReportRuntime_Create(int argc, char *argv[argc])
+{
+ LongBowReportConfig *result = longBowMemory_Allocate(sizeof(LongBowReportConfig));
+
+ return result;
+}
+
+void
+longBowReportRuntime_Destroy(LongBowReportConfig **reportPtr)
+{
+ longBowMemory_Deallocate((void **) reportPtr);
+}
+
+void
+longBowReportRuntime_Event(const LongBowEvent *event)
+{
+ if (longBowEventType_IsSuppressAlert(longBowEvent_GetEventType(event)) == false) {
+ char *location = strdup("");
+ if (longBowEvent_GetLocation(event) != NULL) {
+ free(location);
+ location = longBowLocation_ToString(longBowEvent_GetLocation(event));
+ }
+ printf("%s %s %s %s\r\n",
+ longBowEvent_GetName(event), location, longBowEvent_GetKind(event), longBowEvent_GetMessage(event));
+
+ if (longBowEventType_IsSuppressBacktrace(longBowEvent_GetEventType(event)) == false) {
+ char **strs = longBowEvent_CreateSymbolicCallstack(event);
+ if (strs != NULL) {
+ for (size_t i = 0; i < longBowEvent_GetCallStackLength(event); ++i) {
+ fputs(strs[i], stdout);
+ fputs("\r\n", stdout);
+ }
+ free(strs);
+ }
+ }
+ fflush(stdout);
+
+ free(location);
+ }
+}
+
+void
+longBowReportRuntime_Message(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+}
+
+void
+longBowReportRuntime_Warning(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ printf("WARNING ");
+ vprintf(format, args);
+ va_end(args);
+}
+
+void
+longBowReportRuntime_Error(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ printf("ERROR ");
+ vprintf(format, args);
+ va_end(args);
+}
diff --git a/longbow/src/LongBow/Reporting/TextPlain/longBowReport_Testing.c b/longbow/src/LongBow/Reporting/TextPlain/longBowReport_Testing.c
new file mode 100755
index 00000000..3bed5cac
--- /dev/null
+++ b/longbow/src/LongBow/Reporting/TextPlain/longBowReport_Testing.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 <stdio.h>
+#include <assert.h>
+
+#include <LongBow/Reporting/longBowReport_Testing.h>
+#include <LongBow/private/longBow_String.h>
+
+static const LongBowTestRunner *
+_testRunnerSilent(const LongBowTestRunner *testRunner)
+{
+ LongBowStatus status = longBowTestRunner_GetStatus(testRunner);
+
+ printf("%s %s\n", longBowTestRunner_GetName(testRunner), longBowStatus_ToString(status));
+ return testRunner;
+}
+
+static const LongBowTestRunner *
+_testRunnerDetail(const LongBowTestRunner *testRunner)
+{
+ size_t nFixtures = longBowTestRunner_GetFixtureCount(testRunner);
+
+ printf("\r\n");
+ printf("%s: %zd fixture%s\r\n", longBowTestRunner_GetName(testRunner), nFixtures, (nFixtures == 1 ? "" : "s"));
+
+ for (size_t i = 0; i < nFixtures; i++) {
+ LongBowTestFixture *fixture = longBowTestRunner_GetFixture(testRunner, i);
+ longBowReportTesting_TestFixture(fixture);
+ }
+ return testRunner;
+}
+
+const LongBowTestRunner *
+longBowReportTesting_TestRunner(const LongBowTestRunner *testRunner)
+{
+ if (longBowConfig_GetBoolean(longBowTestRunner_GetConfiguration(testRunner), false, "silent")) {
+ return _testRunnerSilent(testRunner);
+ } else {
+ return _testRunnerDetail(testRunner);
+ }
+}
+
+static unsigned int
+_totalSucceeded(const LongBowTestFixtureSummary *summary)
+{
+ return summary->totalSucceeded + summary->totalWarned + summary->totalTearDownWarned;
+}
+
+static unsigned int
+_totalWarned(const LongBowTestFixtureSummary *summary)
+{
+ return summary->totalWarned + summary->totalTearDownWarned;
+}
+
+static unsigned int
+_totalFailed(const LongBowTestFixtureSummary *summary)
+{
+ return summary->totalFailed + summary->totalSignalled + summary->totalStopped + summary->totalTearDownFailed;
+}
+
+static unsigned int
+_totalIncomplete(const LongBowTestFixtureSummary *summary)
+{
+ return summary->totalSetupFailed + summary->totalSkipped + summary->totalUnimplemented;
+}
+
+static void
+_reportSummary(const LongBowTestFixture *testFixture)
+{
+ const LongBowTestFixtureSummary *summary = longBowTestFixture_GetSummary(testFixture);
+
+ char *fixtureString = longBowTestFixture_ToString(testFixture);
+
+ printf("%s: Ran %u test case%s.", fixtureString, summary->totalTested, summary->totalTested == 1 ? "" : "s");
+ free(fixtureString);
+
+ if (summary->totalTested > 0) {
+ printf(" %d%% (%d) succeeded", _totalSucceeded(summary) * 100 / summary->totalTested, _totalSucceeded(summary));
+
+ if (_totalWarned(summary) > 0) {
+ printf(" %d%% (%d) with warnings", _totalWarned(summary) * 100 / _totalSucceeded(summary), _totalWarned(summary));
+ }
+ if (_totalFailed(summary) != 0) {
+ printf(", %d%% (%d) failed", _totalFailed(summary) * 100 / summary->totalTested, _totalFailed(summary));
+ }
+ if (_totalIncomplete(summary) > 0) {
+ printf(", %d%% (%d) incomplete", _totalIncomplete(summary) * 100 / summary->totalTested, _totalIncomplete(summary));
+ }
+ }
+ printf("\n");
+}
+
+const LongBowTestFixture *
+longBowReportTesting_TestFixture(const LongBowTestFixture *testFixture)
+{
+ size_t nTestCases = longBowTestFixture_GetTestCaseCount(testFixture);
+
+ _reportSummary(testFixture);
+
+ for (size_t i = 0; i < nTestCases; i++) {
+ LongBowTestCase *testCase = longBowTestFixture_GetTestCase(testFixture, i);
+ longBowReportTesting_TestCase(testCase);
+ }
+ return testFixture;
+}
+
+const LongBowTestCase *
+longBowReportTesting_TestCase(const LongBowTestCase *testCase)
+{
+ LongBowRuntimeResult *testCaseResult = longBowTestCase_GetActualResult(testCase);
+
+ char *rusageString = longBowReportRuntime_RUsageToString(longBowRuntimeResult_GetRUsage(testCaseResult));
+
+ char *elapsedTimeString = longBowReportRuntime_TimevalToString(longBowRuntimeResult_GetElapsedTime(testCaseResult));
+
+ char *statusString = longBowStatus_ToString(longBowTestCase_GetActualResult(testCase)->status);
+ char *testCaseString = longBowTestCase_ToString(testCase);
+
+ LongBowString *string = longBowString_CreateFormat("%10s %s %s %zd %s\n",
+ testCaseString,
+ elapsedTimeString,
+ rusageString,
+ longBowRuntimeResult_GetEventEvaluationCount(longBowTestCase_GetActualResult(testCase)),
+ statusString);
+ longBowString_Write(string, stdout);
+ longBowString_Destroy(&string);
+
+ free(testCaseString);
+ free(statusString);
+ free(elapsedTimeString);
+ free(rusageString);
+
+ return testCase;
+}
+
+void
+longBowReportTesting_DisplayTestCaseResult(const LongBowTestCase *testCase)
+{
+ const LongBowRuntimeResult *testCaseResult = longBowTestCase_GetActualResult(testCase);
+
+ switch (testCaseResult->status) {
+ case LongBowStatus_UNTESTED: printf("X"); break;
+ case LONGBOW_STATUS_SUCCEEDED: printf("."); break;
+ case LONGBOW_STATUS_SKIPPED: printf("S"); break;
+ case LongBowStatus_WARNED: printf("W"); break;
+ case LONGBOW_STATUS_SETUP_FAILED: printf("s"); break;
+ case LONGBOW_STATUS_TEARDOWN_FAILED: printf("t"); break;
+ case LongBowStatus_TEARDOWN_WARNED: printf("w"); break;
+ case LONGBOW_STATUS_FAILED: printf("F"); break;
+ case LongBowStatus_STOPPED: printf("T"); break;
+ case LongBowStatus_UNIMPLEMENTED: printf("U"); break;
+ case LongBowStatus_IMPOTENT: printf("I"); break;
+ default:
+ if (testCaseResult->status >= LongBowStatus_SIGNALLED) {
+ printf("K");
+ } else {
+ printf("?");
+ }
+ }
+ fflush(stdout);
+}
+
+void
+longBowReportTesting_Trace(const char *restrict format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ char *message;
+ if (vasprintf(&message, format, ap) == -1) {
+ return;
+ }
+ va_end(ap);
+
+ printf("%s\n", message);
+ free(message);
+}
diff --git a/longbow/src/LongBow/Reporting/longBowReport_Runtime.c b/longbow/src/LongBow/Reporting/longBowReport_Runtime.c
new file mode 100755
index 00000000..2671cf31
--- /dev/null
+++ b/longbow/src/LongBow/Reporting/longBowReport_Runtime.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 <LongBow/Reporting/longBowReport_Runtime.h>
+
+char *
+longBowReportRuntime_TimevalToString(const struct timeval time)
+{
+ char *string = NULL;
+ if (asprintf(&string, "%ld.%06lds", time.tv_sec, (long) time.tv_usec) == -1) {
+ return NULL;
+ }
+ return string;
+}
+
+char *
+longBowReportRuntime_RUsageToString(const struct rusage *rusage)
+{
+ char *string;
+
+ char *ru_utime = longBowReportRuntime_TimevalToString(rusage->ru_utime);
+ char *ru_stime = longBowReportRuntime_TimevalToString(rusage->ru_stime);
+
+ if (asprintf(&string, "%s %s", ru_utime, ru_stime) == -1) {
+ return NULL;
+ }
+
+ free(ru_utime);
+ free(ru_stime);
+
+ return string;
+}
diff --git a/longbow/src/LongBow/Reporting/longBowReport_Runtime.h b/longbow/src/LongBow/Reporting/longBowReport_Runtime.h
new file mode 100755
index 00000000..5682be15
--- /dev/null
+++ b/longbow/src/LongBow/Reporting/longBowReport_Runtime.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 Reporting/longBowReport_Runtime.h
+ * @ingroup reporting
+ * @brief The LongBow Runtime Report Generator.
+ *
+ * This header specifies the interface for an implementation of a LongBow Test Report generator.
+ * Different implementations of a Test Report generator are used to connect to external environments to hook in
+ * LongBow unit tests within a larger framework like an IDE or continuous integration system.
+ *
+ * There may be many different ways to report the summary of a LongBow Unit Test,
+ * and the different ways implement the functions prescribed here.
+ * The resulting object files are then linked with the unit-test according to the kind of report needed.
+ *
+ */
+#ifndef LONGBOW_REPORT_RUNTIME_H_
+#define LONGBOW_REPORT_RUNTIME_H_
+
+#include <LongBow/longBow_Event.h>
+
+#include <LongBow/runtime.h>
+#include <LongBow/unit-test.h>
+
+struct longbow_report_config;
+/**
+ * @brief Configuration for a LongBow Test.
+ */
+typedef struct longbow_report_config LongBowReportConfig;
+
+/**
+ * @struct longbow_report_config
+ * @brief The configuration information for a LongBow Test Report.
+ */
+struct longbow_report_config {
+ struct {
+ unsigned int untested : 1;
+ unsigned int succeeded : 1;
+ unsigned int warned : 1;
+ unsigned int teardown_warned : 1;
+ unsigned int skipped : 1;
+ unsigned int unimplemented : 1;
+ unsigned int failed : 1;
+ unsigned int stopped : 1;
+ unsigned int teardown_failed : 1;
+ unsigned int setup_failed : 1;
+ unsigned int signalled : 1;
+ } suppress_report; /**< Bit fields representing which report to suppress. */
+};
+
+/**
+ * Create a LongBowReportConfiguration from a set of parameters.
+ *
+ * @param [in] argc The number of parameters in the argv array.
+ * @param [in] argv An array of C strings.
+ *
+ * @return An allocated LongBowReportConfiguration instance that must be dellocted via longBowReport_Destroy.
+ *
+ * Example:
+ * @code
+ * {
+ * char *argv[2] = { "arg1", "arg2" };
+ * LongBowReportConfig *report = longBowReport_Create(2, argv);
+ * }
+ * @endcode
+ */
+LongBowReportConfig *longBowReportRuntime_Create(int argc, char *argv[]);
+
+/**
+ * Destroy a LongBowReportConfig instance.
+ *
+ * @param [in,out] configPtr A pointer to a LongBowReportConfig pointer. The value of configPtr will be set to zero.
+ *
+ * Example:
+ * @code
+ * {
+ * char *argv[2] = { "arg1", "arg2" };
+ * LongBowReportConfig *report = longBowReport_Create(2, argv);
+ * LongBowReport_Destroy(&report);
+ * }
+ * @endcode
+ */
+void longBowReportRuntime_Destroy(LongBowReportConfig **configPtr);
+
+/**
+ * Report a LongBowEvent.
+ *
+ * @param [in] event A pointer to a valid LongBowEvent instance.
+ */
+void longBowReportRuntime_Event(const LongBowEvent *event);
+
+/**
+ * Report a message.
+ *
+ * @param [in] message A pointer to a nul-terminated C string.
+ */
+void longBowReportRuntime_Message(const char *message, ...);
+
+/**
+ * Report an error message.
+ *
+ * An error message reports an unrecoverable error.
+ *
+ * @param [in] message A pointer to a nul-terminated C string.
+ */
+void longBowReportRuntime_Error(const char *message, ...);
+
+/**
+ * Report an error message.
+ *
+ * An error message reports an recoverable warning.
+ *
+ * @param [in] message A pointer to a nul-terminated C string.
+ */
+void longBowReportRuntime_Warning(const char *message, ...);
+
+/**
+ * Format a struct timeval structure.
+ *
+ * @param [in] time A struct timeval value.
+ *
+ * @return An allocated nul-terminated C string that must be freed via stdlib free(3).
+ */
+char *longBowReportRuntime_TimevalToString(const struct timeval time);
+
+/**
+ * Format a struct rusage struture.
+ *
+ * @param [in] rusage A pointer to a valid `struct rusage` instance.
+ * @return An allocated nul-terminated C string that must be freed via stdlib free(3).
+ */
+char *longBowReportRuntime_RUsageToString(const struct rusage *rusage);
+#endif // LONGBOW_REPORT_RUNTIME_H_
diff --git a/longbow/src/LongBow/Reporting/longBowReport_Testing.c b/longbow/src/LongBow/Reporting/longBowReport_Testing.c
new file mode 100755
index 00000000..646a7a05
--- /dev/null
+++ b/longbow/src/LongBow/Reporting/longBowReport_Testing.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+
+#include <LongBow/Reporting/longBowReport_Testing.h>
diff --git a/longbow/src/LongBow/Reporting/longBowReport_Testing.h b/longbow/src/LongBow/Reporting/longBowReport_Testing.h
new file mode 100755
index 00000000..b4b2eaf8
--- /dev/null
+++ b/longbow/src/LongBow/Reporting/longBowReport_Testing.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.
+ */
+
+/**
+ * @file longBowReport_Testing.h
+ * @ingroup reporting
+ * @brief The LongBow Test Report Generator.
+ *
+ * This header specifies the interface for an implementation of a LongBow Test Report generator.
+ * Different implementations of a Test Report generator are used to connect to external environments to hook in
+ * LongBow unit tests within a larger framework like an IDE or continuous integration system.
+ *
+ */
+#ifndef LONGBOW_REPORT_TESTING_H_
+#define LONGBOW_REPORT_TESTING_H_
+
+#include <LongBow/Reporting/longBowReport_Runtime.h>
+
+#include <LongBow/runtime.h>
+#include <LongBow/unit-test.h>
+
+/**
+ * Produce a summary report for the given LongBowTestRunner.
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ * @return The given LongBowTestRunner.
+ */
+const LongBowTestRunner *longBowReportTesting_TestRunner(const LongBowTestRunner *testRunner);
+
+/**
+ * Produce a summary report for the given LongBowTestFixture.
+ *
+ * @param [in] testFixture A pointer to a LongBowTestFixture instance.
+ * @return The given LongBowTestFixture.
+ */
+const LongBowTestFixture *longBowReportTesting_TestFixture(const LongBowTestFixture *testFixture);
+
+/**
+ * Produce a summary report for the given LongBowTestCase.
+ *
+ * @param [in] testCase A pointer to a LongBowTestCase instance.
+ * @return The pointer to the given LongBowTestCase.
+ */
+const LongBowTestCase *longBowReportTesting_TestCase(const LongBowTestCase *testCase);
+
+/**
+ * Produce a single character displaying the status of an individual test case.
+ *
+ * @param [in] testCase A pointer to a LongBowTestCase instance.
+ */
+void longBowReportTesting_DisplayTestCaseResult(const LongBowTestCase *testCase);
+
+/**
+ * Make a trace report.
+ *
+ * @param [in] format A printf-style format string.
+ */
+void longBowReportTesting_Trace(const char *restrict format, ...);
+#endif // LONGBOW_REPORT_TESTING_H_
diff --git a/longbow/src/LongBow/assertions.h b/longbow/src/LongBow/assertions.h
new file mode 100644
index 00000000..c175bb1d
--- /dev/null
+++ b/longbow/src/LongBow/assertions.h
@@ -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.
+ */
+
+/**
+ * @file assertions.h
+ * @ingroup runtime
+ * @brief Runtime and Test Assertions
+ *
+ */
+#ifndef LongBow_assertions_h
+#define LongBow_assertions_h
+
+#ifndef LongBow_runtime_h
+#error "Do not include LongBow/assertions.h directly. Include LongBow/runtime.h"
+#endif
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <LongBow/traps.h>
+#include <LongBow/tests.h>
+
+#include <LongBow/longBow_Location.h>
+#include <LongBow/longBow_Event.h>
+
+/**
+ * @def assertTrue
+ * @brief Assert that a condition is true.
+ *
+ * @param condition If false, the assertion triggers.
+ * @param ... A printf formatting string (required) and parameters (optional).
+ *
+ * Example:
+ * @code
+ * {
+ * assertTrue(2 + 2 == 4, "Adding 2 + 2 did not equal 4.");
+ * }
+ * @endcode
+ */
+#define assertTrue(condition, ...) longBowAssert(&LongBowAssertEvent, (condition), __VA_ARGS__)
+
+/**
+ * @def assertFalse
+ * @brief Assert that a condition is false.
+ *
+ * @param condition If true, the assertion triggers.
+ * @param ... A printf formatting string (required) and parameters (optional).
+ * Example:
+ * @code
+ * {
+ * assertFalse(2 + 2 == 5, "Adding 2 + 2 must not equal 5.");
+ * }
+ * @endcode
+ */
+#define assertFalse(condition, ...) longBowAssert(&LongBowAssertEvent, !(condition), __VA_ARGS__)
+
+/**
+ * @def assertNotNull
+ * @brief Assert that the given value is not NULL.
+ *
+ * @param x If the value is NULL, the assertion triggers.
+ * @param ... A printf formatting string (required) and parameters (optional).
+ * Example:
+ * @code
+ * void
+ * function(char *p)
+ * {
+ * assertNotNull(p, "Parameter must not be NULL");
+ * }
+ * @endcode
+ */
+#define assertNotNull(x, ...) longBowAssert(&LongBowAssertEvent, (x) != NULL, __VA_ARGS__)
+
+/**
+ * @def assertNull
+ * @brief Assert that the given value is NULL.
+ *
+ * @param x The value to test.
+ * @param ... A printf formatting string (required) and parameters (optional).
+ * Example:
+ * @code
+ * void
+ * function(char *p)
+ * {
+ * assertNull(p, "Parameter must be NULL");
+ * }
+ * @endcode
+ */
+#define assertNull(x, ...) longBowAssert(&LongBowAssertEvent, (x) == NULL, __VA_ARGS__)
+
+/**
+ * @def assertAligned
+ * @brief Assert that the given address is aligned according to `alignment`.
+ *
+ * Return true of the given address is aligned according to alignment.
+ * The value for alignment must be a power of 2.
+ *
+ * @param address A pointer to memory
+ * @param alignment A power of 2 representing the memory alignment of address.
+ * @param ... A printf formatting string (required) and parameters (optional).
+ *
+ * Example:
+ * @code
+ * void
+ * function(void *p)
+ * {
+ * assertAligned(p, 4, "Parameter must be aligned on 4 byte boundaries");
+ * }
+ * @endcode
+ */
+#define assertAligned(address, alignment, ...) \
+ longBowAssert(&LongBowAssertEvent, longBowRuntime_TestAddressIsAligned((address), (alignment)), __VA_ARGS__)
+
+/**
+ * @def assertEqualStrings
+ * @brief Assert that two strings are equal.
+ *
+ * @param expected
+ * @param actual
+ * @param ... A printf formatting string (required) and parameters (optional).
+ *
+ * Example:
+ * @code
+ * {
+ * assertEqualStrings("hello", "world");
+ * }
+ * @endcode
+ */
+#define assertEqualStrings(expected, actual) \
+ longBowAssert(&LongBowAssertEvent, strcmp((expected), (actual)) == 0, "Expected '%s' actual '%s'", (expected), (actual))
+
+/**
+ * @def assertEqual
+ * @brief Assert that two values are equal, using a canonical string message.
+ */
+#define assertEqual(expected, actual, format) \
+ assertTrue((expected) == (actual), "Expected=" format " actual=" format, (expected), (actual))
+#endif /* ASSERTIONS_H_ */
+
diff --git a/longbow/src/LongBow/command-line/.gitignore b/longbow/src/LongBow/command-line/.gitignore
new file mode 100644
index 00000000..c12b3061
--- /dev/null
+++ b/longbow/src/LongBow/command-line/.gitignore
@@ -0,0 +1,2 @@
+liblongbow-config
+*dSYM
diff --git a/longbow/src/LongBow/command-line/liblongbow-config.c b/longbow/src/LongBow/command-line/liblongbow-config.c
new file mode 100755
index 00000000..5e7bf6cc
--- /dev/null
+++ b/longbow/src/LongBow/command-line/liblongbow-config.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <string.h>
+
+#define stringify(x) "" #x ""
+
+void
+printLoaderDirectory(void)
+{
+ printf("%s\n", LIB_INSTALL_DIR);
+}
+
+void
+printIncludeDirectory(void)
+{
+}
+
+void
+printVersion(void)
+{
+}
+
+int
+main(int argc, char *argv[])
+{
+ for (int i = 1; i < argc; i++) {
+ if (strcmp("-I", argv[i]) == 0) {
+ printIncludeDirectory();
+ } else if (strcmp("-L", argv[i]) == 0) {
+ printLoaderDirectory();
+ } else if (strcmp("-v", argv[i]) == 0) {
+ printVersion();
+ } else {
+ printf("unknown option '%s'\n", argv[i]);
+ }
+ }
+ return 0;
+}
diff --git a/longbow/src/LongBow/config.h.in b/longbow/src/LongBow/config.h.in
new file mode 100644
index 00000000..75a5edc2
--- /dev/null
+++ b/longbow/src/LongBow/config.h.in
@@ -0,0 +1,11 @@
+//
+// Created by Ignacio Solis on 12/1/15.
+//
+
+#ifndef LONGBOW_CONFIGURATION_H
+#define LONGBOW_CONFIGURATION_H
+
+#define LIB_INSTALL_DIR "@CMAKE_INSTALL_PREFIX@"
+
+#endif //LONGBOW_CONFIGURATION_H
+
diff --git a/longbow/src/LongBow/debugging.h b/longbow/src/LongBow/debugging.h
new file mode 100755
index 00000000..b19ca486
--- /dev/null
+++ b/longbow/src/LongBow/debugging.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 debugging.h
+ * @brief Debugging Utilities
+ *
+ */
+#ifndef LongBow_debugging_h
+#define LongBow_debugging_h
+
+#include <LongBow/longBow_Debug.h>
+
+#include <LongBow/longBow_MeasureTime.h>
+
+/**
+ * @def longBow_function
+ * @brief The compile time function name.
+ */
+#if __STDC_VERSION__ >= 199901L
+# define longBow_function __func__
+#else
+# define longBow_function ((const char *) 0)
+#endif
+
+/**
+ * @def longBowDebug
+ * @brief Print a debugging message.
+ *
+ * @param ... A printf-style format string followed by a variable number of parameters supplying values for the format string.
+ */
+#ifndef LONGBOW_DEBUG_DISABLED
+# define longBowDebug(...) \
+ do { longBowDebug_Message(NULL, longBowLocation_Create(__FILE__, longBow_function, __LINE__), __VA_ARGS__); } while (0)
+#else
+# define longBowDebug(...) \
+ do { } while (0)
+#endif
+#endif
diff --git a/longbow/src/LongBow/longBow_About.c b/longbow/src/LongBow/longBow_About.c
new file mode 100644
index 00000000..1a29eacf
--- /dev/null
+++ b/longbow/src/LongBow/longBow_About.c
@@ -0,0 +1,44 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170214.46e2c73a 2017-02-14T20:35:31Z
+
+#include "longBow_About.h"
+
+const char *longBow_What = "@(#)" "longBow " RELEASE_VERSION " 2017-02-14T21:35:02.945622"
+ "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates.";
+
+const char *
+longBowAbout_Name(void)
+{
+ return "longBow";
+}
+
+const char *
+longBowAbout_Version(void)
+{
+ return RELEASE_VERSION;
+}
+
+const char *
+longBowAbout_About(void)
+{
+ return "longBow "RELEASE_VERSION " 2017-02-14T21:35:02.945622" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+longBowAbout_MiniNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+longBowAbout_ShortNotice(void)
+{
+ return "Copyright (c) 2017 Cisco and/or its affiliates.\n";
+}
+
+const char *
+longBowAbout_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\n\n";
+}
+
diff --git a/longbow/src/LongBow/longBow_About.h b/longbow/src/LongBow/longBow_About.h
new file mode 100755
index 00000000..5941aa6a
--- /dev/null
+++ b/longbow/src/LongBow/longBow_About.h
@@ -0,0 +1,54 @@
+// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.
+// longbow-generate-about 1.0.20170214.46e2c73a 2017-02-14T20:35:31Z
+
+#ifndef longBow_About_h
+#define longBow_About_h
+/**
+ * Embedded string containing information for the what(1) command.
+ *
+ */
+extern const char *longBow_What;
+
+/**
+ * Return the name as a C string.
+ *
+ * @return The name as a C string.
+ */
+const char *longBowAbout_Name(void);
+
+/**
+ * Return the version as a C string.
+ *
+ * @return The version as a C string.
+ */
+const char *longBowAbout_Version(void);
+
+/**
+ * Return the About text as a C string.
+ *
+ * @return The About text as a C string.
+ */
+const char *longBowAbout_About(void);
+
+/**
+ * Return the minimum copyright notice as a C string.
+ *
+ * @return The minimum copyright notice as a C string.
+ */
+const char *longBowAbout_MiniNotice(void);
+
+/**
+ * Return the short copyright notice as a C string.
+ *
+ * @return The short copyright notice as a C string.
+ */
+const char *longBowAbout_ShortNotice(void);
+
+/**
+ * Return the long copyright notice as a C string.
+ *
+ * @return The long copyright notice as a C string.
+ */
+const char *longBowAbout_LongNotice(void);
+
+#endif // longBow_About_h
diff --git a/longbow/src/LongBow/longBow_Backtrace.c b/longbow/src/LongBow/longBow_Backtrace.c
new file mode 100755
index 00000000..19625eed
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Backtrace.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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <LongBow/longBow_Backtrace.h>
+#include <LongBow/private/longBow_Memory.h>
+
+#if defined(_WIN64)
+# define backtrace(...) (0)
+# define backtrace_symbols(...) 0
+# define backtrace_symbols_fd(...) ((void) 0)
+#elif defined(_WIN32)
+# define backtrace(...) (0)
+# define backtrace_symbols(...) 0
+# define backtrace_symbols_fd(...) ((void) 0)
+#elif defined(__ANDROID__)
+# define backtrace(...) (0)
+# define backtrace_symbols(...) 0
+# define backtrace_symbols_fd(...) ((void) 0)
+#elif defined(__APPLE__)
+# include <execinfo.h>
+#elif defined(__linux)
+# include <execinfo.h>
+#elif defined(__unix) // all unices not caught above
+# define backtrace(...) (0)
+# define backtrace_symbols(...) 0
+# define backtrace_symbols_fd(...) ((void) 0)
+#elif defined(__posix)
+# include <execinfo.h>
+#endif
+
+struct longbow_backtrace {
+ void *callstack;
+ unsigned int frames;
+ unsigned int offset;
+};
+
+LongBowBacktrace *
+longBowBacktrace_Create(uint32_t maximumFrames, uint32_t offset)
+{
+ LongBowBacktrace *result = longBowMemory_Allocate(sizeof(LongBowBacktrace));
+
+ if (maximumFrames > 0) {
+ void **stackTrace = longBowMemory_Allocate(sizeof(stackTrace[0]) * ((size_t) maximumFrames + offset));
+
+ unsigned int frames = (unsigned int) backtrace(stackTrace, (int) (maximumFrames + offset));
+ if (frames > offset) {
+ unsigned int actualFrames = frames - offset;
+
+ if (actualFrames > maximumFrames) {
+ actualFrames = maximumFrames;
+ }
+
+ // Shift out the first 'offset' number of frames in the stack trace.
+ memmove(&stackTrace[0], &stackTrace[offset], actualFrames * sizeof(stackTrace[0]));
+
+ result->callstack = stackTrace;
+ result->frames = actualFrames;
+ result->offset = 0;
+ }
+ }
+
+ return result;
+}
+
+unsigned int
+longBowBacktrace_GetFrameCount(const LongBowBacktrace *backtrace)
+{
+ return backtrace->frames;
+}
+
+void
+longBowBacktrace_Destroy(LongBowBacktrace **backtracePtr)
+{
+ LongBowBacktrace *backtrace = *backtracePtr;
+ longBowMemory_Deallocate(&backtrace->callstack);
+ longBowMemory_Deallocate((void **) backtracePtr);
+}
+
+char **
+longBowBacktrace_Symbols(const LongBowBacktrace *backtrace)
+{
+ char **result = NULL;
+ if (backtrace != NULL) {
+ result = backtrace_symbols(backtrace->callstack, (int) backtrace->frames);
+ }
+
+ return result;
+}
+
+char *
+longBowBacktrace_ToString(const LongBowBacktrace *backtrace)
+{
+ char *result = NULL;
+
+ char **lines = longBowBacktrace_Symbols(backtrace);
+
+ if (lines == NULL) {
+ result = longBowMemory_StringCopy("(backtrace symbols not supported)");
+ } else {
+ size_t sum = 0;
+ for (int i = 0; i < backtrace->frames; i++) {
+ sum += strlen(lines[i]) + 1;
+ }
+ result = longBowMemory_Allocate(sum + 1 * sizeof(char));
+
+ char *offset = result;
+ for (int i = 0; i < backtrace->frames; i++) {
+ strcpy(offset, lines[i]);
+ offset += strlen(lines[i]);
+ *offset++ = '\n';
+ }
+ *offset = 0;
+ }
+
+ return result;
+}
diff --git a/longbow/src/LongBow/longBow_Backtrace.h b/longbow/src/LongBow/longBow_Backtrace.h
new file mode 100755
index 00000000..b7b12bef
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Backtrace.h
@@ -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.
+ */
+
+/**
+ * @file longBow_Backtrace.h
+ * @ingroup internals
+ * @brief Support for Stack Traces
+ *
+ */
+#ifndef LongBow_longBow_Backtrace_h
+#define LongBow_longBow_Backtrace_h
+#include <stdint.h>
+
+struct longbow_backtrace;
+/**
+ * @typedef LongBowBacktrace
+ * @brief A Backtrace representation.
+ */
+typedef struct longbow_backtrace LongBowBacktrace;
+
+/**
+ * Create a `LongBowBacktrace`.
+ *
+ * The backtrace includes depth number of elements from the stack.
+ *
+ * @param [in] depth The number of elements from the stack to include.
+ * @param [in] offset The offset of the stack to start the Backtrace.
+ * @return A pointer to an allocated LongBowBacktrace instance.
+ */
+LongBowBacktrace *longBowBacktrace_Create(uint32_t depth, uint32_t offset);
+
+/**
+ * Get the array of symbols from the given `LongBowBacktrace instance`.
+ *
+ * @param [in] backtrace A pointer to a valid LongBowBacktrace instance.
+ *
+ * @return An array of nul-terminated, C strings each containing a symbolic representatino of the corresponding stack frame.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+char **longBowBacktrace_Symbols(const LongBowBacktrace *backtrace);
+/**
+ * Get the number of frames in the given LongBowBacktrace instance.
+ *
+ * @param [in] backtrace A pointer to a valid LongBowBacktrace instance.
+ *
+ * @return The number of frames in the LongBowBacktrace.
+ */
+unsigned int longBowBacktrace_GetFrameCount(const LongBowBacktrace *backtrace);
+
+/**
+ *
+ * @param [in,out] backtracePtr A pointer to a pointer to a valid LongBowBacktrace instance.
+ */
+void longBowBacktrace_Destroy(LongBowBacktrace **backtracePtr);
+
+/**
+ *
+ * @param [in] backtrace A pointer to a valid LongBowBacktrace instance.
+ * @return An allocated C string that must be deallocated via longBowMemory_Deallocate().
+ */
+char *longBowBacktrace_ToString(const LongBowBacktrace *backtrace);
+#endif
diff --git a/longbow/src/LongBow/longBow_ClipBoard.c b/longbow/src/LongBow/longBow_ClipBoard.c
new file mode 100644
index 00000000..a3264d44
--- /dev/null
+++ b/longbow/src/LongBow/longBow_ClipBoard.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/longBow_ClipBoard.h>
+
+#include <LongBow/private/longBow_Memory.h>
+#include <LongBow/private/longBow_ArrayList.h>
+
+struct LongBowClipBoard {
+ LongBowArrayList *list;
+};
+
+typedef struct Property {
+ const char *name;
+ char *value;
+} _Property;
+
+static void
+_property_Destroy(_Property **pointer)
+{
+ _Property *property = *pointer;
+ longBowMemory_Deallocate((void **) &property->name);
+ longBowMemory_Deallocate((void **) property);
+}
+
+void
+longBowClipBoard_Destroy(LongBowClipBoard **pointer)
+{
+ LongBowClipBoard *clipboard = *pointer;
+
+ longBowArrayList_Destroy(&clipboard->list);
+ longBowMemory_Deallocate((void **) pointer);
+}
+
+LongBowClipBoard *
+longBowClipBoard_Create(void)
+{
+ LongBowClipBoard *result = longBowMemory_Allocate(sizeof(LongBowClipBoard));
+
+ if (result != NULL) {
+ result->list = longBowArrayList_Create((void (*)(void **))_property_Destroy);
+ }
+
+ return result;
+}
+
+static _Property *
+_longBowClipBoard_Get(const LongBowClipBoard *clipBoard, const char *name)
+{
+ _Property *result = NULL;
+
+ for (size_t index = 0; index < longBowArrayList_Length(clipBoard->list); index++) {
+ _Property *property = longBowArrayList_Get(clipBoard->list, index);
+ if (strcmp(property->name, name) == 0) {
+ result = property;
+ break;
+ }
+ }
+ return result;
+}
+
+void *
+longBowClipBoard_Get(const LongBowClipBoard *clipBoard, const char *name)
+{
+ _Property *property = _longBowClipBoard_Get(clipBoard, name);
+
+ if (property != NULL) {
+ return property->value;
+ }
+
+ return NULL;
+}
+
+char *
+longBowClipBoard_GetAsCString(const LongBowClipBoard *clipBoard, const char *name)
+{
+ return (char *) longBowClipBoard_Get(clipBoard, name);
+}
+
+uint64_t
+longBowClipBoard_GetAsInt(const LongBowClipBoard *clipBoard, const char *name)
+{
+ return (uint64_t) longBowClipBoard_Get(clipBoard, name);
+}
+
+void *
+longBowClipBoard_Set(LongBowClipBoard *clipBoard, const char *name, void *value)
+{
+ void *result = NULL;
+
+ _Property *property = _longBowClipBoard_Get(clipBoard, name);
+ if (property == NULL) {
+ property = longBowMemory_Allocate(sizeof(_Property));
+ property->name = longBowMemory_StringCopy(name);
+ property->value = value;
+ longBowArrayList_Add(clipBoard->list, property);
+ } else {
+ result = property->value;
+ property->value = value;
+ }
+ return result;
+}
+
+void *
+longBowClipBoard_SetInt(LongBowClipBoard *clipBoard, const char *name, uint64_t value)
+{
+ return longBowClipBoard_Set(clipBoard, name, (void *) (uintptr_t) value);
+}
+
+void *
+longBowClipBoard_SetCString(LongBowClipBoard *clipBoard, const char *name, char *value)
+{
+ return longBowClipBoard_Set(clipBoard, name, (char *) value);
+}
+
+bool
+longBowClipBoard_Exists(const LongBowClipBoard *clipBoard, const char *name)
+{
+ return (_longBowClipBoard_Get(clipBoard, name) != NULL);
+}
+
+bool
+longBowClipBoard_Delete(LongBowClipBoard *clipBoard, const char *name)
+{
+ bool result = false;
+
+ for (size_t index = 0; index < longBowArrayList_Length(clipBoard->list); index++) {
+ _Property *property = longBowArrayList_Get(clipBoard->list, index);
+ if (strcmp(property->name, name) == 0) {
+ longBowArrayList_RemoveAtIndex(clipBoard->list, index);
+ result = true;
+ }
+ }
+
+ return result;
+}
diff --git a/longbow/src/LongBow/longBow_ClipBoard.h b/longbow/src/LongBow/longBow_ClipBoard.h
new file mode 100755
index 00000000..86781953
--- /dev/null
+++ b/longbow/src/LongBow/longBow_ClipBoard.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 longBow_ClipBoard.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef longBow_ClipBoard_h
+#define longBow_ClipBoard_h
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct LongBowClipBoard;
+typedef struct LongBowClipBoard LongBowClipBoard;
+
+void longBowClipBoard_Destroy(LongBowClipBoard **pointer);
+
+LongBowClipBoard *longBowClipBoard_Create(void);
+
+void *longBowClipBoard_Get(const LongBowClipBoard *clipBoard, const char *name);
+
+char *longBowClipBoard_GetAsCString(const LongBowClipBoard *clipBoard, const char *name);
+
+uint64_t longBowClipBoard_GetAsInt(const LongBowClipBoard *clipBoard, const char *name);
+
+void *longBowClipBoard_Set(LongBowClipBoard *clipBoard, const char *name, void *value);
+
+void *longBowClipBoard_SetInt(LongBowClipBoard *clipBoard, const char *name, uint64_t value);
+
+void *longBowClipBoard_SetCString(LongBowClipBoard *clipBoard, const char *name, char *value);
+
+bool longBowClipBoard_Exists(const LongBowClipBoard *clipBoard, const char *name);
+
+bool longBowClipBoard_Delete(LongBowClipBoard *clipBoard, const char *name);
+
+#endif /* longBow_ClipBoard_h */
diff --git a/longbow/src/LongBow/longBow_Compiler.h b/longbow/src/LongBow/longBow_Compiler.h
new file mode 100755
index 00000000..197e1e8c
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Compiler.h
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 longBow_Compiler.h
+ * @ingroup compiling
+ * @brief LongBow compile time functionality.
+ *
+ */
+#ifndef LongBow_compiling_h
+#define LongBow_compiling_h
+
+/**
+ * @def LONGBOW_GNUC_EXACTLY
+ *
+ * Compile-time test to determine if the compiler is the GNU C compiler with the specfied
+ * version, revision and patch levels.
+ *
+ * @param [in] major The required major version number of the compiler.
+ * @param [in] minor The required minor version number of the compiler.
+ * @param [in] patch The required patch number of the compiler.
+ *
+ * @return true If the current compiler matches the requirements.
+ *
+ * Example:
+ * @code
+ * #if LONGBOW_GNUC_EXACTLY(4,2,1)
+ * printf("Hello GNU compiler 4.2.1\n");
+ * #endif
+ * @endcode
+ *
+ * @see LONGBOW_GNUC_ATLEAST
+ */
+#ifdef __GNUC__
+# define LONGBOW_GNUC_EXACTLY(major, minor, patch) \
+ (__GNUC__ == major) && (__GNUC_MINOR__ = minor) && (__GNUC_PATCHLEVEL__ == patch)
+#else
+# define LONGBOW_GNUC_EXACTLY(major, minor, patch) \
+ (0)
+#endif
+
+/**
+ * @def LONGBOW_GNUC_ATLEAST
+ *
+ * Compile-time test to determine if the compiler is the GNU C compiler with at least the specfied
+ * version, revision and patch levels.
+ *
+ * @param [in] major The minimum required major version number of the compiler.
+ * @param [in] minor The minimum required minor version number of the compiler.
+ * @param [in] patch The minimum required patch number of the compiler.
+ *
+ * @return true If the current compiler matches the requirements.
+ * @return false If the current compiler fails to match the requirements.
+ *
+ * Example:
+ * @code
+ * #if LONGBOW_GNUC_ATLEAST(4,0,0)
+ * printf("Hello GNU compiler 4.x\n");
+ * #endif
+ * @endcode
+ *
+ * @see LONGBOW_GNUC_EXACTLY
+ */
+#ifdef __GNUC__
+# define LONGBOW_GNUC_ATLEAST(major, minor, patch) \
+ (__GNUC__ >= major) && (__GNUC_MINOR__ > minor) && (__GNUC_PATCHLEVEL__ >= patch)
+#else
+# define LONGBOW_GNUC_ATLEAST(major, minor, patch) \
+ (0)
+#endif
+
+/**
+ * @def LONGBOW_CLANG_EXACTLY
+ *
+ * Compile-time test to determine if the compiler is the Clang C compiler with the specfied
+ * version, revision and patch levels.
+ *
+ * @param [in] major The required major version number of the compiler.
+ * @param [in] minor The required minor version number of the compiler.
+ * @param [in] patch The required patch number of the compiler.
+ *
+ * @return true If the current compiler matches the requirements.
+ *
+ * Example:
+ * @code
+ * #if LONGBOW_CLANG_EXACTLY(5,0,0)
+ * printf("Hello Clang 5.0.0\n");
+ * #endif
+ * @endcode
+ *
+ * @see LONGBOW_CLANG_ATLEAST
+ */
+#ifdef __clang__
+# define LONGBOW_CLANG_EXACTLY(major, minor, patch) \
+ (__clang_major__ == major) && (__clang_major__ = minor) && (__clang_patchlevel__ == patch)
+#else
+# define LONGBOW_CLANG_EXACTLY(major, minor, patch) \
+ (0)
+#endif
+
+/**
+ * @def LONGBOW_CLANG_ATLEAST
+ *
+ * Compile-time test to determine if the compiler is the GNU C compiler with at least the specfied
+ * version, revision and patch levels.
+ *
+ * @param [in] major The minimum required major version number of the compiler.
+ * @param [in] minor The minimum required minor version number of the compiler.
+ * @param [in] patch The minimum required patch number of the compiler.
+ *
+ * @return true If the current compiler matches the requirements.
+ * @return false If the current compiler fails to match the requirements.
+ *
+ * Example:
+ * @code
+ * #if LONGBOW_CLANG_ATLEAST(5,0,0)
+ * printf("Hello Clang compiler 5.x\n");
+ * #endif
+ * @endcode
+ *
+ * @see LONGBOW_CLANG_EXACTLY
+ */
+#ifdef __clang__
+# define LONGBOW_CLANG_ATLEAST(major, minor, patch) \
+ (__clang_major__ >= major) && (__clang_major__ > minor) && (__clang_patchlevel__ >= patch)
+#else
+# define LONGBOW_CLANG_ATLEAST(major, minor, patch) \
+ (0)
+#endif
+
+/**
+ * @def LONGBOW_START_DEPRECATED_WARNINGS
+ *
+ * Compile-time preprocessing to signal the compiler to not report the use of deprecated functions.
+ *
+ * Example:
+ * @code
+ * LONGBOW_STOP_DEPRECATED_WARNINGS
+ * someDeprecatedFunction();
+ * @endcode
+ *
+ * @see LONBOW_STOP_DEPRECATED_WARNINGS
+ */
+
+/**
+ * @def LONGBOW_STOP_DEPRECATED_WARNINGS
+ *
+ * Compile-time preprocessing to signal the compiler to report the use of deprecated functions.
+ *
+ * Example:
+ * @code
+ * LONGBOW_STOP_DEPRECATED_WARNINGS
+ * someDeprecatedFunction();
+ * @endcode
+ *
+ * @see LONBOW_START_DEPRECATED_WARNINGS
+ */
+#if LONGBOW_CLANG_ATLEAST(5, 0, 0) || LONGBOW_GNUC_ATLEAST(4, 6, 0)
+# define LONGBOW_STOP_DEPRECATED_WARNINGS \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
+
+# define LONGBOW_START_DEPRECATED_WARNINGS \
+ _Pragma("GCC diagnostic pop")
+
+#elif __clang__ || __GNUC__
+
+# define LONGBOW_STOP_DEPRECATED_WARNINGS \
+ _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
+
+# define LONGBOW_START_DEPRECATED_WARNINGS \
+ _Pragma("GCC diagnostic warning \"-Wdeprecated-declarations\"")
+
+#else
+
+# define LONGBOW_STOP_DEPRECATED_WARNINGS /* nothing */
+
+# define LONGBOW_START_DEPRECATED_WARNINGS /* nothing */
+#endif
+
+/**
+ * @def LongBowCompiler_IgnoreInitializerOverrides
+ *
+ * Compile-time preprocessing to signal the compiler to not report the use of structure initializer overrides.
+ *
+ * Example:
+ * @code
+ * LongBowCompiler_IgnoreInitializerOverrides
+ * struct foo {
+ * int a;
+ * } instance = {
+ * .a = 1,
+ * .a = 1
+ * };
+ * LongBowCompiler_WarnInitializerOverrides
+ * @endcode
+ *
+ * @see LongBowCompiler_WarnInitializerOverrides
+ */
+#if LONGBOW_CLANG_ATLEAST(5, 0, 0)
+# define LongBowCompiler_IgnoreInitializerOverrides \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Winitializer-overrides\"")
+
+# define LongBowCompiler_WarnInitializerOverrides \
+ _Pragma("GCC diagnostic pop")
+
+#elif LONGBOW_GNUC_ATLEAST(4, 6, 0)
+# define LongBowCompiler_IgnoreInitializerOverrides \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Woverride-init\"")
+
+# define LongBowCompiler_WarnInitializerOverrides \
+ _Pragma("GCC diagnostic pop")
+
+#elif __clang__ || __GNUC__
+# define LongBowCompiler_IgnoreInitializerOverrides \
+ _Pragma("GCC diagnostic ignored \"-Woverride-init\"")
+
+# define LongBowCompiler_WarnInitializerOverrides \
+ _Pragma("GCC diagnostic warning \"-Woverride-init\"")
+
+#else
+
+# define LongBowCompiler_IgnoreInitializerOverrides /* nothing */
+
+# define LongBowCompiler_WarnInitializerOverrides /* nothing */
+#endif
+
+/**
+ * @def LONGBOW_STOPWARNINGS_UnusedVariable
+ *
+ * Compile-time preprocessing to signal the compiler to report unused variables.
+ *
+ * Example:
+ * @code
+ * LONGBOW_STOPWARNINGS_UnusedVariable
+ * void
+ * foo(int unusedVariable)
+ * {
+ * return;
+ * }
+ * LONGBOW_STARTWARNINGS_UnusedVariable
+ * @endcode
+ *
+ * @see LONGBOW_STARTWARNINGS_UnusedVariable
+ *
+ * @def LONGBOW_STARTWARNINGS_UnusedVariable
+ *
+ * Compile-time preprocessing to signal the compiler to report unused variables.
+ *
+ * Example:
+ * @code
+ * LONGBOW_STOPWARNINGS_UnusedVariable
+ * void
+ * foo(int unusedVariable)
+ * {
+ * return;
+ * }
+ * LONGBOW_STARTWARNINGS_UnusedVariable
+ * @endcode
+ *
+ * @see LONGBOW_STARTWARNINGS_UnusedVariable
+ */
+#if LONGBOW_CLANG_ATLEAST(5, 0, 0)
+# define LONGBOW_STOPWARNINGS_UnusedVariable \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wunused-variable\"")
+# define LONGBOW_STARTWARNINGS_UnusedVariable \
+ _Pragma("GCC diagnostic pop")
+#elif LONGBOW_GNUC_ATLEAST(4, 6, 0)
+# define LONGBOW_STOPWARNINGS_UnusedVariable \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wunused-variable\"")
+# define LONGBOW_STARTWARNINGS_UnusedVariable \
+ _Pragma("GCC diagnostic pop")
+#elif __clang__ || __GNUC__
+# define LONGBOW_STOPWARNINGS_UnusedVariable \
+ _Pragma("GCC diagnostic ignored \"-Wunused-variable\"")
+# define LONGBOW_STARTWARNINGS_UnusedVariable \
+ _Pragma("GCC diagnostic warning \"-Wunused-variable\"")
+#else
+
+# define LONGBOW_STOPWARNINGS_UnusedVariable /* nothing */
+
+# define LONGBOW_STARTWARNINGS_UnusedVariable /* nothing */
+#endif
+
+
+#endif // LongBow_compiling_h
diff --git a/longbow/src/LongBow/longBow_Config.c b/longbow/src/LongBow/longBow_Config.c
new file mode 100755
index 00000000..f650661f
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Config.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <inttypes.h>
+
+#include <LongBow/private/longBow_ArrayList.h>
+#include <LongBow/private/longBow_Memory.h>
+#include <LongBow/private/longBow_String.h>
+
+#include <LongBow/longBow_Properties.h>
+
+#include <LongBow/longBow_Config.h>
+#include <LongBow/Reporting/longBowReport_Runtime.h>
+#include <LongBow/longBow_About.h>
+
+/** @cond private */
+struct longbow_configuration {
+ LongBowReportConfig *reportConfiguration;
+ LongBowProperties *properties;
+};
+/** @endcond */
+
+static void
+_longBowConfig_SetupEnvironment(const LongBowConfig *config)
+{
+}
+
+static void
+_longBowConfig_Show(const LongBowConfig *configuration)
+{
+ char *string = longBowProperties_ToString(configuration->properties);
+ ssize_t nwritten = write(1, string, strlen(string));
+ if (nwritten != strlen(string)) {
+ fprintf(stderr, "Failed to write to file descriptor 1.\n");
+ exit(-1);
+ }
+ longBowMemory_Deallocate((void **) &string);
+}
+
+static bool
+_longBowConfig_Set(LongBowConfig *configuration, const char *expression)
+{
+ bool result = false;
+
+ LongBowArrayList *tokens = longBowString_Tokenise(expression, "=");
+ if (tokens != NULL) {
+ if (longBowArrayList_Length(tokens) == 2) {
+ char *name = longBowArrayList_Get(tokens, 0);
+ char *value = longBowArrayList_Get(tokens, 1);
+ result = longBowConfig_SetProperty(configuration, name, value);
+ longBowArrayList_Destroy(&tokens);
+ }
+ }
+
+ return result;
+}
+
+LongBowConfig *
+longBowConfig_Create(int argc, char *argv[], const char *mainFileName)
+{
+ LongBowConfig *result = longBowMemory_Allocate(sizeof(LongBowConfig));
+
+ result->properties = longBowProperties_Create();
+ longBowProperties_Set(result->properties, "trace", "false");
+ longBowProperties_Set(result->properties, "silent", "false");
+ longBowProperties_Set(result->properties, "run-forked", "false");
+
+ for (int i = 1; i < argc; i++) {
+ if (longBowString_Equals("--help", argv[i]) || longBowString_Equals("-h", argv[i])) {
+ // If the option is "--help",
+ // then let all of the sub-systems that also take arguments process that option also.
+ printf("LongBow %s\n", longBowAbout_Version());
+ printf("%s\n", longBowAbout_MiniNotice());
+ printf("Options\n");
+ //printf(" --main Print the name of the main test runner source file.\n");
+ printf(" --help Print this help message.\n");
+ printf(" --run-forked Run the tests as forked processes.\n");
+ printf(" --run-nonforked Run the tests in the same process (default).\n");
+ printf(" --version Print the version of LongBow used for this test.\n");
+ printf(" --core-dump Produce a core file upon the first failed assertion.\n");
+ printf(" --set name=value Set a configuration property name to the specified value\n");
+ longBowTestRunner_ConfigHelp();
+ longBowTestFixture_ConfigHelp();
+ longBowTestCase_ConfigHelp();
+ longBowReportRuntime_Create(argc, argv);
+ longBowConfig_Destroy(&result);
+ printf("\n");
+ return NULL;
+ } else if (longBowString_Equals("--main", argv[i])) {
+ printf("%s\n", mainFileName);
+ longBowConfig_Destroy(&result);
+ return NULL;
+ } else if (longBowString_Equals("--version", argv[i])) {
+ printf("%s\n", longBowAbout_Version());
+ longBowConfig_Destroy(&result);
+ return NULL;
+ } else if (longBowString_Equals("--run-nonforked", argv[i])) {
+ longBowProperties_Set(result->properties, "run-forked", "false");
+ } else if (longBowString_Equals("--run-forked", argv[i])) {
+ printf("?\n");
+ longBowProperties_Set(result->properties, "run-forked", "true");
+ } else if (longBowString_Equals("--trace", argv[i])) {
+ longBowProperties_Set(result->properties, "trace", "true");
+ } else if (longBowString_Equals("--silent", argv[i])) {
+ longBowProperties_Set(result->properties, "silent", "true");
+ } else if (longBowString_Equals("--core-dump", argv[i])) {
+ longBowProperties_Set(result->properties, "core-dump", "true");
+ } else if (longBowString_StartsWith(argv[i], "--set")) {
+ char *parameter = argv[++i];
+ if (_longBowConfig_Set(result, parameter) == false) {
+ printf("Could not set parameter: %s\n", parameter);
+ }
+ } else if (longBowString_StartsWith(argv[i], "--show")) {
+ _longBowConfig_Show(result);
+ } else {
+ printf("Unknown option '%s'\n", argv[i]);
+ }
+ }
+
+ LongBowReportConfig *reportConfiguration = longBowReportRuntime_Create(argc, argv);
+
+ if (reportConfiguration == NULL) {
+ longBowConfig_Destroy(&result);
+ result = NULL;
+ } else {
+ if (result == NULL) {
+ // nothing to do.
+ } else {
+ result->reportConfiguration = reportConfiguration;
+ }
+ }
+
+ if (result != NULL) {
+ _longBowConfig_SetupEnvironment(result);
+ }
+ return result;
+}
+
+void
+longBowConfig_Destroy(LongBowConfig **configPtr)
+{
+ LongBowConfig *config = *configPtr;
+
+ if (config != NULL) {
+ if (config->reportConfiguration != NULL) {
+ longBowReportRuntime_Destroy(&config->reportConfiguration);
+ }
+ longBowProperties_Destroy(&config->properties);
+ longBowMemory_Deallocate((void **) configPtr);
+ }
+}
+
+bool
+longBowConfig_IsRunForked(const LongBowConfig *config)
+{
+ return longBowConfig_GetBoolean(config, false, "run-forked");
+}
+
+bool
+longBowConfig_IsTrace(const LongBowConfig *config)
+{
+ return longBowConfig_GetBoolean(config, false, "trace");
+}
+
+static const char *
+_longBowConfig_GetProperty(const LongBowConfig *config, const char *format, va_list ap)
+{
+ const char *result = NULL;
+
+ char *propertyName;
+ if (vasprintf(&propertyName, format, ap) != -1) {
+ if (config != NULL && config->properties != NULL) {
+ result = longBowProperties_Get(config->properties, propertyName);
+ }
+ free(propertyName);
+ }
+
+ return result;
+}
+
+const char *
+longBowConfig_GetProperty(const LongBowConfig *config, const char *format, ...)
+{
+ const char *result = NULL;
+
+ if (config != NULL && config->properties != NULL) {
+ va_list ap;
+ va_start(ap, format);
+ result = _longBowConfig_GetProperty(config, format, ap);
+ va_end(ap);
+ }
+
+ return result;
+}
+
+bool
+longBowConfig_SetProperty(const LongBowConfig *config, const char *name, const char *value)
+{
+ bool result = false;
+
+ if (config != NULL && config->properties != NULL) {
+ result = longBowProperties_Set(config->properties, name, value);
+ }
+
+ return result;
+}
+
+bool
+longBowConfig_GetBoolean(const LongBowConfig *config, bool defaultValue, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ const char *value = _longBowConfig_GetProperty(config, format, ap);
+ va_end(ap);
+
+ bool result = defaultValue;
+ if (value != NULL) {
+ result = (strcasecmp(value, "true") == 0);
+ }
+ return result;
+}
+
+uint32_t
+longBowConfig_GetUint32(const LongBowConfig *config, uint32_t defaultValue, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ const char *value = _longBowConfig_GetProperty(config, format, ap);
+ va_end(ap);
+
+ uint32_t result = defaultValue;
+ if (value != NULL) {
+ result = (uint32_t) strtoul(value, NULL, 10);
+ }
+ return result;
+}
diff --git a/longbow/src/LongBow/longBow_Config.h b/longbow/src/LongBow/longBow_Config.h
new file mode 100755
index 00000000..003497b4
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Config.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 longBow_Config.h
+ * @ingroup internals
+ * @brief Support for LongBow Configuration
+ *
+ */
+#ifndef LONGBOWCONFIGURATION_H_
+#define LONGBOWCONFIGURATION_H_
+#include <stdbool.h>
+#include <stdint.h>
+
+struct longbow_configuration;
+
+/**
+ * @typedef LongBowConfig
+ * @brief The LongBow Configuration
+ */
+typedef struct longbow_configuration LongBowConfig;
+
+/**
+ * Destroy a LongBowConfig instance.
+ *
+ * @param [in,out] configPtr A pointer to a LongBowConfig instance pointer.
+ */
+void longBowConfig_Destroy(LongBowConfig **configPtr);
+
+/**
+ * Create a LongBowConfig structure instance from the given array of parameters.
+ *
+ * The function parses argv style arguments and composes a LongBowConfig structure.
+ *
+ * The argv-style arguments may include parameters not related to creating a LongBowConfig structure.
+ *
+ * For example, the arguments may only be `--help` and prints a help message but doesn't create a `LongBowConfig` structure.
+ *
+ * @param [in] argc The number of elements in the `argv` array.
+ * @param [in] argv An array of nul-terminated C strings.
+ * @param [in] mainFileName The string printed for the `--main` option.
+ *
+ * @return non-NULL A LongBowConfig structure instance suitable for running a test
+ * @return NULL Nothing suitable for running a test (not an error).
+ */
+LongBowConfig *longBowConfig_Create(int argc, char *argv[], const char *mainFileName);
+
+/**
+ * Get a property stored in the configuration.
+ * @param [in] config A pointer to a valid LongBowConfig instance.
+ * @param [in] format A pointer to a valid, nul-terminated format string.
+ *
+ * @return non-NULL A pointer to nul-terminated, C string.
+ */
+const char *longBowConfig_GetProperty(const LongBowConfig *config, const char *format, ...);
+
+/**
+ * Set the property @p name to @p value
+ *
+ * @param [in] config A pointer to a valid LongBowConfig instance.
+ *
+ * @return true
+ * @return true
+ */
+bool longBowConfig_SetProperty(const LongBowConfig *config, const char *name, const char *value);
+
+/**
+ * Get the property @p name interpreted as a 32-bit integer.
+ *
+ * @param [in] config A pointer to a valid LongBowConfig instance.
+ *
+ * @return The property @p name interpreted as a 32-bit integer.
+ */
+uint32_t longBowConfig_GetUint32(const LongBowConfig *config, uint32_t defaultValue, const char *format, ...);
+
+/**
+ * Get the value of the configuration property named by the formatted property name.
+ * If the given LongBowConfig instance is not available, or the property is not present, the default value is returned.
+ *
+ * @param [in] config A pointer to a valid LongBowConfig instance.
+ * @param [in] defaultValue Either true or false.
+ * @param [in] format A printf format string followed by appropriate parameters used to construct the property name.
+ *
+ * @return true The property was present with the value true, or the property was not present and the default value is true.
+ * @return false The property was present with the value false, or the property was not present and the default value is false.
+ */
+bool longBowConfig_GetBoolean(const LongBowConfig *config, bool defaultValue, const char *format, ...);
+
+/**
+ * Return `true` if the given `LongBowConfig` instance specifies that test cases are to be run in a sub-process.
+ *
+ * @param [in] config A pointer to a valid LongBowConfig instance.
+ * @return true if the given specification stipulates tests are to run in a sub-process.
+ */
+bool longBowConfig_IsRunForked(const LongBowConfig *config);
+
+/**
+ * Indicate if the given configuration is specifying the 'trace' flag.
+ *
+ * @param [in] config A pointer to a valid LongBowConfig instance.
+ *
+ * @return true The given configuration is specifying the 'trace' flag.
+ * @return false The given configuration is not specifying the 'trace' flag.
+ *
+ * Example:
+ * @code
+ * if (longBowConfig_IsTrace(longBowRunner_GetConfiguration(testRunner)) {
+ * longBowTrace_Report(testRunner->configuration);
+ * }
+ * @endcode
+ */
+bool longBowConfig_IsTrace(const LongBowConfig *config);
+
+#endif // LONGBOWCONFIGURATION_H_
diff --git a/longbow/src/LongBow/longBow_Debug.c b/longbow/src/LongBow/longBow_Debug.c
new file mode 100755
index 00000000..6a72603f
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Debug.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 <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <LongBow/longBow_Debug.h>
+#include <LongBow/Reporting/longBowReport_Runtime.h>
+
+/** @cond */
+struct longbow_debug_criteria {
+ bool enabled;
+};
+/** @endcond */
+
+static struct longbow_debug_criteria LongBowDebug_StaticCriteria = {
+ .enabled = true
+};
+
+static LongBowDebugCriteria *LongBowDebug_CurrentCriteria = &LongBowDebug_StaticCriteria;
+
+LongBowDebugCriteria *
+longBowDebug_CurrentCriteria(void)
+{
+ return LongBowDebug_CurrentCriteria;
+}
+
+static void
+_longBowDebug_MemoryDumpLine(const char *memory, size_t offset, size_t length)
+{
+ int bytesPerLine = 16;
+ char accumulator[bytesPerLine + 1];
+ memset(accumulator, ' ', bytesPerLine);
+ accumulator[bytesPerLine] = 0;
+
+ printf("%5zd: ", offset);
+
+ for (size_t i = 0; i < bytesPerLine; i++) {
+ if (offset + i >= length) {
+ printf(" ");
+ accumulator[i] = ' ';
+ } else {
+ char c = memory[offset + i];
+ printf("%02x ", c & 0xFF);
+ if (isprint(c)) {
+ accumulator[i] = c;
+ } else {
+ accumulator[i] = '.';
+ }
+ }
+ }
+ printf(" %s\n", accumulator);
+}
+
+void
+longBowDebug_MemoryDump(const char *memory, size_t length)
+{
+ size_t bytesPerLine = 16;
+
+ for (size_t offset = 0; offset < length; offset += bytesPerLine) {
+ _longBowDebug_MemoryDumpLine(memory, offset, length);
+ }
+}
+
+void
+longBowDebug_Message(LongBowDebugCriteria *criteria, const LongBowLocation *location, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+
+ char *message;
+ int status = vasprintf(&message, format, ap);
+ va_end(ap);
+ if (status != -1) {
+#if 1
+ char *locationString = longBowLocation_ToString(location);
+ longBowReportRuntime_Message("%s %s\r\n", locationString, message);
+
+ free(locationString);
+#else
+ longBowReportRuntime_Message(location, message);
+#endif
+ free(message);
+ }
+}
+
+ssize_t
+longBowDebug_WriteFile(const char *fileName, const char *data, size_t length)
+{
+ ssize_t result = 0;
+
+ int fd = open(fileName, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+ if (fd == -1) {
+ perror(fileName);
+ } else {
+ result = write(fd, data, length);
+ }
+ close(fd);
+ return result;
+}
+
+ssize_t
+longBowDebug_ReadFile(const char *fileName, char **data)
+{
+ ssize_t result = -1;
+ struct stat statbuf;
+ char *buffer;
+
+ int fd = open(fileName, O_RDONLY);
+ if (fd == -1) {
+ perror(fileName);
+ } else {
+ if (fstat(fd, &statbuf) != -1) {
+ buffer = malloc((unsigned long) statbuf.st_size + 1);
+ result = read(fd, buffer, (unsigned long) statbuf.st_size);
+ buffer[statbuf.st_size] = 0;
+ *data = buffer;
+ }
+ }
+ return result;
+}
diff --git a/longbow/src/LongBow/longBow_Debug.h b/longbow/src/LongBow/longBow_Debug.h
new file mode 100755
index 00000000..f92df876
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Debug.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 longBow_Debug.h
+ * @ingroup internals
+ * @brief Support for LongBow and Application Debugging.
+ *
+ */
+#ifndef LongBow_longBow_Debug_h
+#define LongBow_longBow_Debug_h
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <LongBow/longBow_Location.h>
+
+typedef struct longbow_debug_criteria LongBowDebugCriteria;
+
+/**
+ * Pretty print memory on standard output.
+ *
+ * @param [in] memory A pointer to memory.
+ * @param [in] length The number of bytes to display.
+ */
+void longBowDebug_MemoryDump(const char *memory, size_t length);
+
+/**
+ * Generate and send a message to the specified location.
+ *
+ * @param [in] criteria Debug criteria.
+ * @param [in] location The location to which the message is sent.
+ * @param [in] format The format string for the message.
+ * @param [in] ... Remaining arguments for the message string.
+ */
+void longBowDebug_Message(LongBowDebugCriteria *criteria, const LongBowLocation *location, const char *format, ...);
+
+/**
+ * Write data in an array to a file.
+ *
+ * Data is written to the specified file from the supplied array.
+ *
+ * @param [in] fileName The name of the to write to.
+ * @param [in] data A pointer to an array of bytes to write.
+ * @param [in] length The number of bytes to write.
+ *
+ * @return The number of bytes written.
+ *
+ * Example:
+ * @code
+ * {
+ * size_t numBytesWritten = longBowDebug_WriteFile("log.out", "error", 6);
+ * }
+ * @endcode
+ *
+ * @see longBowDebug_ReadFile
+ */
+ssize_t longBowDebug_WriteFile(const char *fileName, const char *data, size_t length);
+
+/**
+ * Read data from a file into an allocated array.
+ *
+ * Data is read from the specified file into an allocated byte array which must be deallocated by the caller via {stdlib free()}.
+ *
+ * For convenience the allocate buffer exceeds the size of the file by one byte, which is set to zero.
+ * This permits using the result directly as a nul-terminated C string.
+ *
+ * @param [in] fileName The name of the file to read from.
+ * @param [in] data A pointer to a character pointer that will be updated with the address of the read data.
+ *
+ * @return The number of bytes read, or -1 if there was an error.
+ *
+ * Example:
+ * @code
+ * {
+ * char *buffer = NULL;
+ * size_t numBytesRead = longBowDebug_ReadFile("log.out", &buffer);
+ * // use buffer as needed
+ * }
+ * @endcode
+ *
+ * @see longBowDebug_WriteFile
+ */
+ssize_t longBowDebug_ReadFile(const char *fileName, char **data);
+#endif
diff --git a/longbow/src/LongBow/longBow_Event.c b/longbow/src/LongBow/longBow_Event.c
new file mode 100755
index 00000000..a24d45bf
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Event.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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <LongBow/longBow_Event.h>
+#include <LongBow/longBow_EventType.h>
+#include <LongBow/longBow_Backtrace.h>
+#include <LongBow/longBow_Location.h>
+#include <LongBow/longBow_Status.h>
+#include <LongBow/private/longBow_Memory.h>
+
+/** @cond private */
+struct longbow_event {
+ const LongBowEventType *type;
+ const LongBowLocation *location;
+ const char *kind;
+ const char *message;
+ const LongBowBacktrace *backtrace;
+};
+/** @endcond */
+
+const char *
+longBowEvent_GetName(const LongBowEvent *event)
+{
+ return longBowEventType_GetName(event->type);
+}
+
+LongBowEvent *
+longBowEvent_Create(const LongBowEventType *eventType, const LongBowLocation *location, const char *kind, const char *message, const LongBowBacktrace *backtrace)
+{
+ LongBowEvent *result = longBowMemory_Allocate(sizeof(LongBowEvent));
+ if (result != NULL) {
+ result->type = eventType;
+ result->location = location;
+ result->kind = kind;
+ result->message = strndup(message, strlen(message));
+ result->backtrace = backtrace;
+ }
+
+ return result;
+}
+
+void
+longBowEvent_Destroy(LongBowEvent **assertionPtr)
+{
+ LongBowEvent *assertion = *assertionPtr;
+
+ if (assertion->location != NULL) {
+ longBowLocation_Destroy((LongBowLocation **) &assertion->location);
+ }
+ if (assertion->message != NULL) {
+ free((void *) assertion->message);
+ }
+
+ if (assertion->backtrace != NULL) {
+ longBowBacktrace_Destroy((LongBowBacktrace **) &assertion->backtrace);
+ }
+ longBowMemory_Deallocate((void **) assertionPtr);
+}
+
+const LongBowLocation *
+longBowEvent_GetLocation(const LongBowEvent *event)
+{
+ return event->location;
+}
+
+const LongBowEventType *
+longBowEvent_GetEventType(const LongBowEvent *event)
+{
+ return event->type;
+}
+
+const char *
+longBowEvent_GetKind(const LongBowEvent *event)
+{
+ return event->kind;
+}
+
+const char *
+longBowEvent_GetMessage(const LongBowEvent *event)
+{
+ return event->message;
+}
+
+const LongBowBacktrace *
+longBowEvent_GetBacktrace(const LongBowEvent *event)
+{
+ return event->backtrace;
+}
+
+char **
+longBowEvent_CreateSymbolicCallstack(const LongBowEvent *event)
+{
+ char **result = longBowBacktrace_Symbols(event->backtrace);
+
+ return result;
+}
+
+size_t
+longBowEvent_GetCallStackLength(const LongBowEvent *event)
+{
+ return longBowBacktrace_GetFrameCount(event->backtrace);
+}
diff --git a/longbow/src/LongBow/longBow_Event.h b/longbow/src/LongBow/longBow_Event.h
new file mode 100755
index 00000000..12f903c0
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Event.h
@@ -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.
+ */
+
+/**
+ * @file longBow_Event.h
+ * @ingroup internals
+ * @brief LongBow Event Support.
+ *
+ * LongBow assertions, traps and tests induce "events" which are experienced by the programme runtime as signals or long-jumps.
+ *
+ */
+#ifndef LongBow_longBow_Event_h
+#define LongBow_longBow_Event_h
+
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include <LongBow/longBow_EventType.h>
+#include <LongBow/longBow_Location.h>
+#include <LongBow/longBow_Backtrace.h>
+
+struct longbow_event;
+
+/**
+ * @typedef LongBowEvent
+ */
+typedef struct longbow_event LongBowEvent;
+
+/**
+ * Get the `LongBowEventType` of a LongBowEvent.
+ *
+ * @param [in] event A `LongBowEvent` instance.
+ *
+ * @return A pointer to the LongBowEventType of the event.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowEvent *event = ...
+ * LongBowEventType type = longBowEvent_GetEventType(event);
+ * }
+ * @endcode
+ */
+const LongBowEventType *longBowEvent_GetEventType(const LongBowEvent *event);
+
+/**
+ * Create a `LongBowEvent`.
+ *
+ * Creating a `LongBowEvent` records runtime data and used by report facilities.
+ * This does not actually cause the process to assert the assertion.
+ *
+ * @param [in] eventType The LongBowEventType for this event.
+ * @param [in] location A LongBowLocation instance recording the location of the event.
+ * @param [in] kind A string representing the kind of event.
+ * @param [in] message A message to display. This will be freed via free(3).
+ * @param [in] backtrace A pointer to a valid LongBowBacktrace instance.
+ *
+ * @return An allocated LongBowEvent which must be destroyed via `longBowEvent_Destroy()`.
+ */
+LongBowEvent *longBowEvent_Create(const LongBowEventType *eventType, const LongBowLocation *location, const char *kind, const char *message, const LongBowBacktrace *backtrace);
+
+/**
+ * Destroy a `LongBowEvent`.
+ *
+ * The value pointed to by `eventPtr`, is set to `NULL.
+ *
+ * @param [in,out] eventPtr The `LongBowEvent` instance to destroy and NULLify.
+ */
+void longBowEvent_Destroy(LongBowEvent **eventPtr);
+
+/**
+ * Get the `LongBowLocation` associated with this `LongBowEvent` instance.
+ *
+ * @param [in] event A `LongBowEvent` instance.
+ *
+ * @return A pointer to the `LongBowLocation` instance for the given `LongBowEvent`.
+ */
+const LongBowLocation *longBowEvent_GetLocation(const LongBowEvent *event);
+
+/**
+ * Get the name.
+ *
+ * @param [in] event A `LongBowEvent` instance.
+ *
+ * @return The name of the given LongBowEvent.
+ */
+const char *longBowEvent_GetName(const LongBowEvent *event);
+
+/**
+ * Get a pointer to the string representing the kind of this event.
+ *
+ * Currently the kind is only a static string set when creating a `LongBowEvent`.
+ *
+ * @param [in] event A pointer to a `LongBowEvent` instance.
+ *
+ * @return non-NULL The pointer to the string representing the kind of this event.
+ * @return NULL The kind was not set.
+ *
+ * @see longBowEvent_Create
+ */
+const char *longBowEvent_GetKind(const LongBowEvent *event);
+
+/**
+ * Retrieve the message associated with this `LongBowEvent` instance.
+ *
+ * @param [in] event A `LongBowEvent` instance.
+ *
+ * @return The message associated with the given `LongBowEvent`.
+ */
+const char *longBowEvent_GetMessage(const LongBowEvent *event);
+
+/**
+ * Get the `LongBowBacktrace` instance for the given `LongBowEvent` instance.
+ *
+ * @param [in] event A pointer to a valid LongBowEvent instance.
+ *
+ * @return A pointer to a LongBowBacktrace instance.
+ */
+const LongBowBacktrace *longBowEvent_GetBacktrace(const LongBowEvent *event);
+
+/**
+ * Get an array of nul-terminated C strings containing the symbolic representation of the given `LongBowEvent` stack backtrace.
+ * The length of the array is provided by `longBowEvent_GetCallStackLength`
+ *
+ * @param [in] event A pointer to a valid `LongBowEvent` instance.
+ *
+ * @return non-NULL An array of nul-terminated C strings
+ * @see longBowEvent_GetCallStackLength
+ */
+char **longBowEvent_CreateSymbolicCallstack(const LongBowEvent *event);
+
+/**
+ * Retrieve the call stack length associated with this `LongBowEvent` instance.
+ *
+ * @param [in] event A `LongBowEvent` instance.
+ *
+ * @return The length of the call stack.
+ */
+size_t longBowEvent_GetCallStackLength(const LongBowEvent *event);
+#endif // LongBow_longBow_Event_h
diff --git a/longbow/src/LongBow/longBow_EventType.c b/longbow/src/LongBow/longBow_EventType.c
new file mode 100755
index 00000000..d1c24620
--- /dev/null
+++ b/longbow/src/LongBow/longBow_EventType.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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <signal.h>
+
+#include <LongBow/longBow_Status.h>
+#include <LongBow/longBow_EventType.h>
+
+/** @cond private */
+struct longbow_event_type {
+ const char *kind;
+ const char *name;
+ LongBowStatus statusCode;
+ bool suppressBacktrace;
+ bool suppressAlert;
+};
+/** @endcond */
+
+#define _eventType(_kind, _name, _code, _suppressBacktrace, _suppressAlert) { \
+ .kind = _kind, \
+ .name = _name, \
+ .statusCode = _code, \
+ .suppressBacktrace = _suppressBacktrace, \
+ .suppressAlert = _suppressAlert \
+}
+
+LongBowEventType LongBowAssertEvent = _eventType("Assert", "Assert", LONGBOW_STATUS_FAILED, false, false);
+
+LongBowEventType LongBowTrapEvent = _eventType("Trap", "Trap", LONGBOW_STATUS_FAILED, false, false);
+
+LongBowEventType LongBowTrapOutOfBounds = _eventType("Trap", "OutOfBounds", LONGBOW_STATUS_FAILED, false, false);
+
+LongBowEventType LongBowTrapIllegalValue = _eventType("Trap", "IllegalValue", LONGBOW_STATUS_FAILED, false, false);
+
+LongBowEventType LongBowTrapInvalidValue = _eventType("Trap", "InvalidValue", LONGBOW_STATUS_FAILED, false, false);
+
+LongBowEventType LongBowTrapUnrecoverableState = _eventType("Trap", "UnrecoverableState", LONGBOW_STATUS_FAILED, false, false);
+
+LongBowEventType LongBowTrapNotImplemented = _eventType("Trap", "Implemented", LONGBOW_STATUS_FAILED, false, false);
+
+LongBowEventType LongBowTrapOutOfMemoryEvent = _eventType("Trap", "Out of Memory", LONGBOW_STATUS_FAILED, false, false);
+
+LongBowEventType LongBowTrapCannotObtainLockEvent = _eventType("Trap", "Cannot obtain lock", LONGBOW_STATUS_FAILED, false, false);
+
+LongBowEventType LongBowTrapUnexpectedStateEvent = _eventType("Trap", "Unexpected State", LONGBOW_STATUS_FAILED, false, false);
+
+LongBowEventType LongBowTestSkippedEvent = _eventType("Test", "Skipped", LONGBOW_STATUS_SKIPPED, true, false);
+
+LongBowEventType LongBowTestUnimplementedEvent = _eventType("Test", "Unimplemented", LongBowStatus_UNIMPLEMENTED, true, true);
+
+LongBowEventType LongBowEventSIGHUP = _eventType("Signal", "SIGHUP", LongBowStatus_SIGNAL(SIGHUP), false, false);
+
+LongBowEventType LongBowEventSIGINT = _eventType("Signal", "SIGINT", LongBowStatus_SIGNAL(SIGINT), false, false);
+
+LongBowEventType LongBowEventSIGQUIT = _eventType("Signal", "SIGQUIT", LongBowStatus_SIGNAL(SIGQUIT), false, false);
+
+LongBowEventType LongBowEventSIGILL = _eventType("Signal", "SIGILL", LongBowStatus_SIGNAL(SIGILL), false, false);
+
+LongBowEventType LongBowEventSIGTRAP = _eventType("Signal", "SIGTRAP", LongBowStatus_SIGNAL(SIGTRAP), false, false);
+
+LongBowEventType LongBowEventSIGABRT = _eventType("Signal", "SIGABRT", LongBowStatus_SIGNAL(SIGABRT), false, false);
+
+#ifdef _DARWIN_C_SOURCE
+LongBowEventType LongBowEventSIGEMT = _eventType("Signal", "SIGEMT", LongBowStatus_SIGNAL(SIGEMT), false, false);
+#else
+LongBowEventType LongBowEventSIGEMT = _eventType("Signal", "SIGBUS", LongBowStatus_SIGNAL(SIGBUS), false, false);
+#endif
+
+LongBowEventType LongBowEventSIGFPE = _eventType("Signal", "SIGFPE", LongBowStatus_SIGNAL(SIGFPE), false, false);
+
+LongBowEventType LongBowEventSIGKILL = _eventType("Signal", "SIGKILL", LongBowStatus_SIGNAL(SIGKILL), false, false);
+
+LongBowEventType LongBowEventSIGBUS = _eventType("Signal", "SIGBUS", LongBowStatus_SIGNAL(SIGBUS), false, false);
+
+LongBowEventType LongBowEventSIGSEGV = _eventType("Signal", "SIGSEGV", LongBowStatus_SIGNAL(SIGSEGV), false, false);
+
+LongBowEventType LongBowEventSIGSYS = _eventType("Signal", "SIGSYS", LongBowStatus_SIGNAL(SIGSYS), false, false);
+
+LongBowEventType LongBowEventSIGPIPE = _eventType("Signal", "SIGPIPE", LongBowStatus_SIGNAL(SIGPIPE), false, false);
+
+LongBowEventType LongBowEventSIGALRM = _eventType("Signal", "SIGALRM", LongBowStatus_SIGNAL(SIGALRM), false, false);
+
+LongBowEventType LongBowEventSIGTERM = _eventType("Signal", "SIGTERM", LongBowStatus_SIGNAL(SIGTERM), false, false);
+
+LongBowEventType LongBowEventSIGURG = _eventType("Signal", "SIGURG", LongBowStatus_SIGNAL(SIGURG), false, false);
+
+LongBowEventType LongBowEventSIGSTOP = _eventType("Signal", "SIGSTOP", LongBowStatus_SIGNAL(SIGSTOP), false, false);
+
+LongBowEventType LongBowEventSIGTSTP = _eventType("Signal", "SIGTSTP", LongBowStatus_SIGNAL(SIGTSTP), false, false);
+
+LongBowEventType LongBowEventSIGCONT = _eventType("Signal", "SIGCONT", LongBowStatus_SIGNAL(SIGCONT), false, false);
+
+LongBowEventType LongBowEventSIGCHLD = _eventType("Signal", "SIGCHLD", LongBowStatus_SIGNAL(SIGCHLD), false, false);
+
+LongBowEventType LongBowEventSIGTTIN = _eventType("Signal", "SIGTTIN", LongBowStatus_SIGNAL(SIGTTIN), false, false);
+
+LongBowEventType LongBowEventSIGTTOU = _eventType("Signal", "SIGTTOU", LongBowStatus_SIGNAL(SIGTTOU), false, false);
+
+LongBowEventType LongBowEventSIGIO = _eventType("Signal", "SIGIO", LongBowStatus_SIGNAL(SIGIO), false, false);
+
+LongBowEventType LongBowEventSIGXCPU = _eventType("Signal", "SIGXCPU", LongBowStatus_SIGNAL(SIGXCPU), false, false);
+
+LongBowEventType LongBowEventSIGXFSZ = _eventType("Signal", "SIGXFSZ", LongBowStatus_SIGNAL(SIGXFSZ), false, false);
+
+LongBowEventType LongBowEventSIGVTALRM = _eventType("Signal", "SIGVTALRM", LongBowStatus_SIGNAL(SIGVTALRM), false, false);
+
+LongBowEventType LongBowEventSIGPROF = _eventType("Signal", "SIGPROF", LongBowStatus_SIGNAL(SIGPROF), false, false);
+
+LongBowEventType LongBowEventSIGWINCH = _eventType("Signal", "SIGWINCH", LongBowStatus_SIGNAL(SIGWINCH), false, false);
+
+#if (!defined (__ANDROID__) && (!defined(_POSIX_C_SOURCE)) || defined(_DARWIN_C_SOURCE))
+LongBowEventType LongBowEventSIGINFO = _eventType("Signal", "SIGINFO", LongBowStatus_SIGNAL(SIGINFO), false, false);
+#else
+LongBowEventType LongBowEventSIGINFO = _eventType("Signal", "SIGIO", LongBowStatus_SIGNAL(SIGIO), false, false);
+#endif
+
+LongBowEventType LongBowEventSIGUSR1 = _eventType("Signal", "SIGUSR1", LongBowStatus_SIGNAL(SIGUSR1), false, false);
+
+LongBowEventType LongBowEventSIGUSR2 = _eventType("Signal", "SIGUSR2", LongBowStatus_SIGNAL(SIGUSR2), false, false);
+
+LongBowEventType LongBowTestEvent = _eventType("Test", "Test", LongBowStatus_WARNED, false, false);
+
+static LongBowEventType *signalToEventType[NSIG] = {
+ NULL,
+ &LongBowEventSIGHUP /* 1 */,
+ &LongBowEventSIGINT /* 2 */,
+ &LongBowEventSIGQUIT /* 3 */,
+ &LongBowEventSIGILL /* 4 */,
+ &LongBowEventSIGTRAP /* 5 */,
+ &LongBowEventSIGABRT /* 6 */,
+ &LongBowEventSIGEMT /* 7 */,
+ &LongBowEventSIGFPE /* 8 */,
+ &LongBowEventSIGKILL /* 9 */,
+ &LongBowEventSIGBUS /* 10 */,
+ &LongBowEventSIGSEGV /* 11 */,
+ &LongBowEventSIGSYS /* 12 */,
+ &LongBowEventSIGPIPE /* 13 */,
+ &LongBowEventSIGALRM /* 14 */,
+ &LongBowEventSIGTERM /* 15 */,
+ &LongBowEventSIGURG /* 16 */,
+ &LongBowEventSIGSTOP /* 17 */,
+ &LongBowEventSIGTSTP /* 18 */,
+ &LongBowEventSIGCONT /* 19 */,
+ &LongBowEventSIGCHLD /* 20 */,
+ &LongBowEventSIGTTIN /* 21 */,
+ &LongBowEventSIGTTOU /* 22 */,
+ &LongBowEventSIGIO /* 23 */,
+ &LongBowEventSIGXCPU /* 24 */,
+ &LongBowEventSIGXFSZ /* 25 */,
+ &LongBowEventSIGVTALRM /* 26 */,
+ &LongBowEventSIGPROF /* 27 */,
+ &LongBowEventSIGWINCH /* 28 */,
+ &LongBowEventSIGINFO /* 29 */,
+ &LongBowEventSIGUSR1 /* 30 */,
+ &LongBowEventSIGUSR2 /* 31 */
+};
+
+const char *
+longBowEventType_GetName(const LongBowEventType *eventType)
+{
+ return eventType->name;
+}
+
+LongBowStatus
+longBowEventType_GetStatus(const LongBowEventType *eventType)
+{
+ return eventType->statusCode;
+}
+
+bool
+longBowEventType_IsSuppressBacktrace(const LongBowEventType *eventType)
+{
+ return eventType->suppressBacktrace;
+}
+
+bool
+longBowEventType_IsSuppressAlert(const LongBowEventType *eventType)
+{
+ return eventType->suppressAlert;
+}
+
+bool
+longBowEventType_Equals(const LongBowEventType *x, const LongBowEventType *y)
+{
+ if (x == y) {
+ return true;
+ }
+ if (x == NULL || y == NULL) {
+ return false;
+ }
+
+ if (strcmp(x->name, y->name) == 0) {
+ return true;
+ }
+ return false;
+}
+
+LongBowEventType *
+longBowEventType_GetEventTypeForSignal(const int signal)
+{
+ return signalToEventType[signal];
+}
+
diff --git a/longbow/src/LongBow/longBow_EventType.h b/longbow/src/LongBow/longBow_EventType.h
new file mode 100755
index 00000000..03774abd
--- /dev/null
+++ b/longbow/src/LongBow/longBow_EventType.h
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 longBow_EventType.h
+ * @ingroup internals
+ * @ingroup runtime
+ * @ingroup testing
+ * @brief LongBow Events and Support.
+ *
+ */
+#ifndef LongBow_longBow_EventType_h
+#define LongBow_longBow_EventType_h
+
+#include <LongBow/longBow_Status.h>
+
+struct longbow_event_type;
+/**
+ * @typedef LongBowEventType
+ *
+ * A LongBowEventType identifies a specific Event induced or generated by a running programme.
+ */
+typedef struct longbow_event_type LongBowEventType;
+
+/**
+ * @var LongBowAssertEvent
+ */
+extern LongBowEventType LongBowAssertEvent;
+
+/**
+ * @var LongBowTestEvent
+ */
+extern LongBowEventType LongBowTestEvent;
+
+/**
+ * @var LongBowTestSkippedEvent
+ */
+extern LongBowEventType LongBowTestSkippedEvent;
+
+/**
+ * @var LongBowTestUnimplementedEvent
+ */
+extern LongBowEventType LongBowTestUnimplementedEvent;
+
+/**
+ * @var LongBowTrapOutOfMemoryEvent
+ */
+extern LongBowEventType LongBowTrapOutOfMemoryEvent;
+
+/**
+ * @var LongBowTrapUnexpectedStateEvent
+ */
+extern LongBowEventType LongBowTrapUnexpectedStateEvent;
+
+/**
+ * @var LongBowTrapEvent
+ */
+extern LongBowEventType LongBowTrapEvent;
+
+/**
+ * @var LongBowTrapOutOfBounds
+ */
+extern LongBowEventType LongBowTrapOutOfBounds;
+
+/**
+ * @var LongBowTrapIllegalValue
+ */
+extern LongBowEventType LongBowTrapIllegalValue;
+
+/**
+ * @var LongBowTrapInvalidValue
+ */
+extern LongBowEventType LongBowTrapInvalidValue;
+
+/**
+ * @var LongBowTrapUnrecoverableState
+ */
+extern LongBowEventType LongBowTrapUnrecoverableState;
+
+/**
+ * @var LongBowTrapNotImplemented
+ */
+extern LongBowEventType LongBowTrapNotImplemented;
+
+/**
+ * @var LongBowTrapCannotObtainLockEvent
+ */
+extern LongBowEventType LongBowTrapCannotObtainLockEvent;
+
+/**
+ * @var LongBowEventSIGHUP
+ */
+extern LongBowEventType LongBowEventSIGHUP;
+
+/**
+ * @var LongBowEventSIGINT
+ */
+extern LongBowEventType LongBowEventSIGINT;
+
+/**
+ * @var LongBowEventSIGQUIT
+ */
+extern LongBowEventType LongBowEventSIGQUIT;
+
+/**
+ * @var LongBowEventSIGILL
+ */
+extern LongBowEventType LongBowEventSIGILL;
+
+/**
+ * @var LongBowEventSIGTRAP
+ */
+extern LongBowEventType LongBowEventSIGTRAP;
+
+/**
+ * @var LongBowEventSIGABRT
+ */
+extern LongBowEventType LongBowEventSIGABRT;
+
+/**
+ * @var LongBowEventSIGIOT
+ */
+extern LongBowEventType LongBowEventSIGIOT;
+
+/**
+ * @var LongBowEventSIGEMT
+ */
+extern LongBowEventType LongBowEventSIGEMT;
+
+/**
+ * @var LongBowEventSIGFPE
+ */
+extern LongBowEventType LongBowEventSIGFPE;
+
+/**
+ * @var LongBowEventSIGKILL
+ */
+extern LongBowEventType LongBowEventSIGKILL;
+
+/**
+ * @var LongBowEventSIGBUS
+ */
+extern LongBowEventType LongBowEventSIGBUS;
+
+/**
+ * @var LongBowEventSIGSEGV
+ */
+extern LongBowEventType LongBowEventSIGSEGV;
+
+/**
+ * @var LongBowEventSIGSYS
+ */
+extern LongBowEventType LongBowEventSIGSYS;
+
+/**
+ * @var LongBowEventSIGPIPE
+ */
+extern LongBowEventType LongBowEventSIGPIPE;
+
+/**
+ * @var LongBowEventSIGALRM
+ */
+extern LongBowEventType LongBowEventSIGALRM;
+
+/**
+ * @var LongBowEventSIGTERM
+ */
+extern LongBowEventType LongBowEventSIGTERM;
+
+/**
+ * @var LongBowEventSIGURG
+ */
+extern LongBowEventType LongBowEventSIGURG;
+
+/**
+ * @var LongBowEventSIGSTOP
+ */
+extern LongBowEventType LongBowEventSIGSTOP;
+
+/**
+ * @var LongBowEventSIGTSTP
+ */
+extern LongBowEventType LongBowEventSIGTSTP;
+
+/**
+ * @var LongBowEventSIGCONT
+ */
+extern LongBowEventType LongBowEventSIGCONT;
+
+/**
+ * @var LongBowEventSIGCHLD
+ */
+extern LongBowEventType LongBowEventSIGCHLD;
+
+/**
+ * @var LongBowEventSIGTTIN
+ */
+extern LongBowEventType LongBowEventSIGTTIN;
+
+/**
+ * @var LongBowEventSIGTTOU
+ */
+extern LongBowEventType LongBowEventSIGTTOU;
+
+/**
+ * @var LongBowEventSIGIO
+ */
+extern LongBowEventType LongBowEventSIGIO;
+
+/**
+ * @var LongBowEventSIGXCPU
+ */
+extern LongBowEventType LongBowEventSIGXCPU;
+
+/**
+ * @var LongBowEventSIGXFSZ
+ */
+extern LongBowEventType LongBowEventSIGXFSZ;
+
+/**
+ * @var LongBowEventSIGVTALRM
+ */
+extern LongBowEventType LongBowEventSIGVTALRM;
+
+/**
+ * @var LongBowEventSIGPROF
+ */
+extern LongBowEventType LongBowEventSIGPROF;
+
+/**
+ * @var LongBowEventSIGWINCH
+ */
+extern LongBowEventType LongBowEventSIGWINCH;
+
+/**
+ * @var LongBowEventSIGINFO
+ */
+extern LongBowEventType LongBowEventSIGINFO;
+
+/**
+ * @var LongBowEventSIGUSR1
+ */
+extern LongBowEventType LongBowEventSIGUSR1;
+
+/**
+ * @var LongBowEventSIGUSR2
+ */
+extern LongBowEventType LongBowEventSIGUSR2;
+
+/**
+ * Determine if two `LongBowEventType` instances are equal.
+ *
+ * The following equivalence relations on non-null `LongBowEventType` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `longBowEventType_Equals(x, x)` must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, `longBowEventType_Equals(x, y)` must return true if and only if
+ * `longBowEventType_Equals(y x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `longBowEventType_Equals(x, y)` returns true and
+ * `longBowEventType_Equals(y, z)` returns true,
+ * then `longBowEventType_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of `longBowEventType_Equals(x, y)`
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, `longBowEventType_Equals(x, NULL)` must return false.
+ *
+ *
+ * @param [in] x A pointer to a `LongBowEventType` instance.
+ * @param [in] y A pointer to a `LongBowEventType` instance.
+ *
+ * @return true `LongBowEventType` x and y are equal.
+ * @return false `LongBowEventType` x and y are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowEventType *e1 = LongBowAssertEvent;
+ * LongBowEventType *e2 = LongBowAssertEvent;
+ *
+ * if (longBowEventType_Equals(bufferA, bufferB)) {
+ * printf("The events are equal.\n");
+ * } else {
+ * printf("The events are NOT equal.\n");
+ * }
+ * }
+ * @endcode
+ */
+bool longBowEventType_Equals(const LongBowEventType *x, const LongBowEventType *y);
+
+/**
+ * Produce a nul-terminated C string representation of this `LongBowEventType` instance.
+ *
+ * @param [in] eventType A pointer to a `LongBowEventType` instance.
+ *
+ * @return The C string name of the given LongBowEventType.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowEventType *event = LongBowAssertEvent;
+ *
+ * printf("Event = %s\n", longBowEventType_GetName(event));
+ * }
+ * @endcode
+ */
+const char *longBowEventType_GetName(const LongBowEventType *eventType);
+
+/**
+ * Test if a `LongBowEventType` is specified to not report a stack backtrace.
+ *
+ * @param [in] eventType A pointer to a `LongBowEventType` instance.
+ *
+ * @return true if the LongBowEventType indicates that a backtrace report is not to be printed.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowEvent *event = ...
+ *
+ * if (longBowEventType_IsSuppressBacktrace(longBowEvent_GetEventType(event)) == false) {
+ * char **strs = longBowEvent_CreateSymbolicCallstack(event);
+ * if (strs != NULL) {
+ * for (size_t i = 0; i < longBowEvent_GetCallStackLength(event); ++i) {
+ * printf("%s\r\n", strs[i]);
+ * }
+ * free(strs);
+ * }
+ * }
+ * }
+ * @endcode
+ */
+bool longBowEventType_IsSuppressBacktrace(const LongBowEventType *eventType);
+
+/**
+ * Test if a LongBowEventType is specified to not report an alert.
+ *
+ * @param [in] eventType A pointer to a `LongBowEventType` instance.
+ *
+ * @return true if the LongBowEventType is specified to not report an alert.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowEvent *event = ...
+ *
+ * if (longBowEventType_IsSuppressAlert(longBowEvent_GetEventType(event)) == false) {
+ * char *location = longBowLocation_ToString(longBowEvent_GetLocation(event));
+ * printf("%s %s %s %s\r\n",
+ * longBowEvent_GetName(event), location, longBowEvent_GetKind(event), longBowEvent_GetMessage(event));
+ *
+ * ...
+ * }
+ *
+ * }
+ * @endcode
+ */
+bool longBowEventType_IsSuppressAlert(const LongBowEventType *eventType);
+
+/**
+ * Get the status of the specified `LongBowEventType` instance.
+ *
+ * @param [in] eventType A pointer to a `LongBowEventType` instance.
+ *
+ * @return The LongBowStatus associated with the given LongBowEventType.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowEvent *event = ...
+ *
+ * LongBowStatus status = longBowEventType_GetStatus(event);
+ * // use the status as needed
+ * }
+ * @endcode
+ */
+LongBowStatus longBowEventType_GetStatus(const LongBowEventType *eventType);
+
+/**
+ * Get the LongBowEventType corresponding to the given signal.
+ *
+ * @param [in] signal The signal to index.
+ *
+ * @return the LongBowEventType corresponding to the given signal.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowEventType *type = longBowEventType_GetEventTypeForSignal(1);
+ * // type is equal to LongBowEventSIGHUP
+ * }
+ * @endcode
+ */
+LongBowEventType *longBowEventType_GetEventTypeForSignal(const int signal);
+#endif // LongBow_longBow_EventType_h
diff --git a/longbow/src/LongBow/longBow_Location.c b/longbow/src/LongBow/longBow_Location.c
new file mode 100755
index 00000000..3d58a11c
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Location.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <LongBow/longBow_Location.h>
+
+#include <LongBow/private/longBow_Memory.h>
+
+/** @cond private */
+struct longbow_location {
+ char *fileName;
+ char *functionName;
+ uint32_t lineNumber;
+};
+/** @endcond */
+
+LongBowLocation *
+longBowLocation_Create(const char *fileName, const char *functionName, uint32_t lineNumber)
+{
+ LongBowLocation *result = longBowMemory_Allocate(sizeof(LongBowLocation));
+
+ if (result != NULL) {
+ result->fileName = (fileName == NULL) ? NULL : strdup(fileName);
+ result->functionName = (functionName == NULL) ? NULL : strdup(functionName);
+ result->lineNumber = lineNumber;
+ }
+
+ return result;
+}
+
+void
+longBowLocation_Destroy(LongBowLocation **locationPtr)
+{
+ assert(locationPtr != NULL);
+
+ LongBowLocation *location = *locationPtr;
+
+ if (location->fileName != NULL) {
+ free(location->fileName);
+ }
+ if (location->functionName != NULL) {
+ free(location->functionName);
+ }
+ longBowMemory_Deallocate((void **) locationPtr);
+}
+
+char *
+longBowLocation_ToString(const LongBowLocation *location)
+{
+ assert(location != NULL);
+
+ char *result;
+
+ if (location->functionName == 0) {
+ int status = asprintf(&result, "%s:%u", location->fileName, location->lineNumber);
+ if (status == -1) {
+ return NULL;
+ }
+ } else {
+ int status = asprintf(&result, "%s:%u %s()", location->fileName, location->lineNumber, location->functionName);
+ if (status == -1) {
+ return NULL;
+ }
+ }
+
+ return result;
+}
diff --git a/longbow/src/LongBow/longBow_Location.h b/longbow/src/LongBow/longBow_Location.h
new file mode 100755
index 00000000..a1e271c3
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Location.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 longBow_Location.h
+ * @ingroup internals
+ * @brief LongBow Source File Location
+ *
+ * LongBow records events during execution and insofar that it's possible,
+ * it records the source code location information for reporting.
+ *
+ */
+#ifndef LongBow_longBow_Location_h
+#define LongBow_longBow_Location_h
+
+#include <stdint.h>
+
+struct longbow_location;
+/**
+ * @typedef LongBowLocation
+ */
+typedef struct longbow_location LongBowLocation;
+
+/**
+ * Create a new LongBow location within a source code file.
+ *
+ * @param [in] fileName The file target of the location.
+ * @param [in] functionName The function target of the location.
+ * @param [in] lineNumber The exact line number within the target file.
+ *
+ * @return A pointer to an allocated LongBowLocation instance that must be deallocated via `longBowLocation_Destroy()`.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowLocation *location = longBowLocation_Create("test.c", "main", 101);
+ * }
+ * @endcode
+ */
+LongBowLocation *longBowLocation_Create(const char *fileName, const char *functionName, uint32_t lineNumber);
+
+/**
+ * Destroy the `LongBowLocation` instance.
+ *
+ * @param [in,out] locationPtr A pointer to the `LongBowLocation` instance to be destroyed.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowLocation *location = longBowLocation_Create("test.c", "main", 101);
+ * ...
+ * longBowLocation_Destroy(&location);
+ * }
+ * @endcode
+ */
+void longBowLocation_Destroy(LongBowLocation **locationPtr);
+
+/**
+ * Create a human readable representation of the `LongBowLocation` instance.
+ *
+ * @param [in] location The `LongBowLocation` instance from which to generate the string representation.
+ *
+ * @return An allocated, null-terminated C string that must be freed via free().
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowLocation *location = longBowLocation_Create("test.c", "main", 101);
+ * char *stringRep = longBowLocation_ToString(location);
+ * ...
+ * longBowLocation_Destroy(&location);
+ * }
+ * @endcode
+ */
+char *longBowLocation_ToString(const LongBowLocation *location);
+#endif // LongBow_longBow_Location_h
diff --git a/longbow/src/LongBow/longBow_Main.c b/longbow/src/LongBow/longBow_Main.c
new file mode 100755
index 00000000..7b3e5c01
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Main.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 <stdarg.h>
+
+#include <LongBow/longBow_Main.h>
+
+#include <LongBow/unit-test.h>
+#include <LongBow/Reporting/longBowReport_Testing.h>
+#include <LongBow/longBow_Config.h>
+
+int
+longBowMain_Impl(int argc, char *argv[argc], ...)
+{
+ LongBowStatus exitStatus = LONGBOW_STATUS_SUCCEEDED;
+
+ // Perform some processing on the input parameters.
+
+ LongBowConfig *config = longBowConfig_Create(argc, argv, NULL);
+ if (config == NULL) {
+ return LONGBOW_STATUS_FAILED;
+ }
+ va_list ap;
+ va_start(ap, argv);
+
+ for (LongBowTestRunner *testRunner = va_arg(ap, LongBowTestRunner *); testRunner != NULL; testRunner = va_arg(ap, LongBowTestRunner *)) {
+ if (testRunner != NULL) {
+ longBowTestRunner_SetConfiguration(testRunner, config);
+ longBowTestRunner_Run(testRunner);
+ longBowReportTesting_TestRunner(testRunner);
+
+ if (!longBowTestRunner_IsSuccessful(testRunner)) {
+ exitStatus = longBowTestRunner_GetStatus(testRunner);
+ }
+ }
+ }
+ va_end(ap);
+
+ longBowConfig_Destroy(&config);
+
+ return (int) exitStatus;
+}
diff --git a/longbow/src/LongBow/longBow_Main.h b/longbow/src/LongBow/longBow_Main.h
new file mode 100755
index 00000000..a3e35a8d
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Main.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 longBow_Main.h
+ * @ingroup testing
+ * @brief A main() function to run one or more LongBow Test Runners.
+ *
+ * The functions in this file provide execution time support for running LongBow Tests.
+ *
+ */
+#ifndef LONGBOWMAIN_H_
+#define LONGBOWMAIN_H_
+
+/**
+ * Run one or more LongBow Test Runners.
+ *
+ * The encapsulating function creates one or more `LongBowTestRunner` instances and supplies
+ * these as a NULL terminated variable argument list to the longBowMain function.
+ * The return value from longBowMain is suitable as an exit status from an executable as zero is success.
+ *
+ * @param [in] argc The number of elements in argv.
+ * @param [in] argv An array of C string arguments.
+ *
+ * @return 0 All tests for all LongBowTestRunners were successful. Otherwise one of `LongBowStatus`.
+ *
+ * Example Usage:
+ * @code
+ * int
+ * main(int argc, char *argv[argc])
+ * {
+ * LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(MyTestRunner);
+ * int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ * longBowTestRunner_Destroy(&testRunner);
+ * exit(exitStatus);
+ * }
+ * @endcode
+ */
+int longBowMain_Impl(int argc, char *argv[], ...);
+#endif /* LONGBOWMAIN_H_ */
diff --git a/longbow/src/LongBow/longBow_MeasureTime.c b/longbow/src/LongBow/longBow_MeasureTime.c
new file mode 100755
index 00000000..2fc566a5
--- /dev/null
+++ b/longbow/src/LongBow/longBow_MeasureTime.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 <config.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+#include <LongBow/longBow_MeasureTime.h>
+#include <LongBow/private/longBow_Memory.h>
+
+struct longBowMeasureTime {
+ struct timeval start;
+ struct timeval stop;
+ unsigned int iterations;
+};
+
+LongBowMeasureTime *
+longBowMeasureTime_Start(unsigned int iterations)
+{
+ LongBowMeasureTime *result = longBowMemory_Allocate(sizeof(LongBowMeasureTime));
+
+ if (result != NULL) {
+ gettimeofday(&result->start, NULL);
+ result->iterations = iterations;
+ result->stop = (struct timeval) { .tv_sec = 0, .tv_usec = 0 };
+ }
+
+ return result;
+}
+
+LongBowMeasureTime *
+longBowMeasureTime_Stop(LongBowMeasureTime *measure)
+{
+ if (measure != NULL) {
+ gettimeofday(&measure->stop, NULL);
+ }
+
+ return measure;
+}
+
+uint64_t
+longBowMeasureTime_GetMicroseconds(const LongBowMeasureTime *measure)
+{
+ struct timeval result;
+ timersub(&(measure->stop), &(measure->start), &result);
+
+ return ((uint64_t) result.tv_sec * 1000000ULL) + ((uint64_t) result.tv_usec);
+}
+
+uint64_t
+longBowMeasureTime_GetNanoseconds(const LongBowMeasureTime *measure)
+{
+ struct timeval result;
+ timersub(&(measure->stop), &(measure->start), &result);
+
+ return ((uint64_t) result.tv_sec * 1000000000ULL) + ((uint64_t) result.tv_usec * 1000);
+}
+
+unsigned int
+longBowMeasureTime_CountDown(LongBowMeasureTime *measure)
+{
+ return measure->iterations--;
+}
+
+bool
+longBowMeasureTime_Report(LongBowMeasureTime *measure, const char *file, const char *function, unsigned int line)
+{
+ struct timeval result;
+ if (measure->stop.tv_sec == 0 && measure->stop.tv_usec == 0) {
+ longBowMeasureTime_Stop(measure);
+ }
+
+ timersub(&(measure->stop), &(measure->start), &result);
+ printf("%s %s %d %ld.%06ld\n", file, function, line, result.tv_sec, (long) result.tv_usec);
+ return true;
+}
+
+void
+longBowMeasureTime_Destroy(LongBowMeasureTime **instancePtr)
+{
+ longBowMemory_Deallocate((void **) instancePtr);
+}
diff --git a/longbow/src/LongBow/longBow_MeasureTime.h b/longbow/src/LongBow/longBow_MeasureTime.h
new file mode 100644
index 00000000..5e2931e0
--- /dev/null
+++ b/longbow/src/LongBow/longBow_MeasureTime.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 longBow_MeasureTime.h
+ *
+ * Measure elapsed time, providing various fetching and reporting mechanisms.
+ *
+ */
+#ifndef __LongBow__longBow_Measure__
+#define __LongBow__longBow_Measure__
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef LongBow_DISABLE_MEASUREMENTS
+# define longBowMeasureTime(_iterations_)
+#else
+# define longBowMeasureTime(_iterations_) for (LongBowMeasureTime *_measure = longBowMeasureTime_Start(_iterations_); \
+ longBowMeasureTime_CountDown(_measure) ? true : (longBowMeasureTime_Report(_measure, __FILE__, __func__, __LINE__), longBowMeasureTime_Destroy(&_measure), false); )
+
+#endif
+
+struct longBowMeasureTime;
+typedef struct longBowMeasureTime LongBowMeasureTime;
+
+/**
+ * Create and start a `LongBowMeasureTime` instance.
+ *
+ * @param [in] iterations The number of iterations to perform when used with `longBowMeasureTime_CountDown`
+ *
+ * @return non-NULL A pointer to a valid LongBowMeasureTime instance that must be destroyed by `longBowMeasureTime_Destroy`
+ */
+LongBowMeasureTime *longBowMeasureTime_Start(unsigned int iterations);
+
+/**
+ * Report on the `LongBowMeasureTime` instance.
+ *
+ * @param [in] measure A pointer to a valid LongBowMeasureTime instance.
+ * @param [in] file A pointer to a nul-terminated C string representing the file name causing the report.
+ * @param [in] function A pointer to a nul-terminated C string representing the function name causing the report.
+ * @param [in] line An unsigned integer representing the line number of the file causing the report.
+ *
+ * @return true The report was successful.
+ */
+bool longBowMeasureTime_Report(LongBowMeasureTime *measure, const char *file, const char *function, unsigned int line);
+
+/**
+ * A simple count-down supporting measurement iterations.
+ *
+ * See {@link longBowMeasureTime} for an example.
+ *
+ * @param [in] measure A pointer to a valid LongBowMeasureTime instance.
+ *
+ * @return The current value of the counter.
+ */
+unsigned int longBowMeasureTime_CountDown(LongBowMeasureTime *measure);
+
+/**
+ * Get the total number of microseconds represented by the `LongBowMeasureTime` instance.
+ *
+ * @param [in] measure A pointer to a valid LongBowMeasureTime instance.
+ *
+ * @return The number of microseconds represented by the `LongBowMeasureTime` instance.
+ */
+uint64_t longBowMeasureTime_GetMicroseconds(const LongBowMeasureTime *measure);
+
+/**
+ * Get the total number of nanoseconds represented by the `LongBowMeasureTime` instance.
+ *
+ * @param [in] measure A pointer to a valid LongBowMeasureTime instance.
+ *
+ * @return The number of nanoseconds represented by the `LongBowMeasureTime` instance.
+ */
+uint64_t longBowMeasureTime_GetNanoseconds(const LongBowMeasureTime *measure);
+
+/**
+ * Destroy a valid `LongBowMeasureTime` instance.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to a valid LongBowMeasureTime instance, that will be set to zero.
+ */
+void longBowMeasureTime_Destroy(LongBowMeasureTime **instancePtr);
+
+#endif /* defined(__LongBow__longBow_Measure__) */
diff --git a/longbow/src/LongBow/longBow_Properties.c b/longbow/src/LongBow/longBow_Properties.c
new file mode 100644
index 00000000..bf5a9da4
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Properties.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <string.h>
+
+#include <LongBow/private/longBow_String.h>
+#include <LongBow/longBow_Properties.h>
+#include <LongBow/private/longBow_ArrayList.h>
+#include <LongBow/private/longBow_Memory.h>
+
+struct LongBowProperties {
+ LongBowArrayList *list;
+};
+
+typedef struct Property {
+ const char *name;
+ const char *value;
+} _Property;
+
+static void
+_property_Destroy(_Property **pointer)
+{
+ _Property *property = *pointer;
+ longBowMemory_Deallocate((void **) &property->name);
+ longBowMemory_Deallocate((void **) &property->value);
+ longBowMemory_Deallocate((void **) property);
+}
+
+LongBowProperties *
+longBowProperties_Create(void)
+{
+ LongBowProperties *result = longBowMemory_Allocate(sizeof(LongBowProperties));
+
+ if (result != NULL) {
+ result->list = longBowArrayList_Create((void (*)(void **))_property_Destroy);
+ }
+
+ return result;
+}
+
+static _Property *
+_longBowProperties_Get(const LongBowProperties *properties, const char *name)
+{
+ _Property *result = NULL;
+
+ for (size_t index = 0; index < longBowArrayList_Length(properties->list); index++) {
+ _Property *property = longBowArrayList_Get(properties->list, index);
+ if (strcmp(property->name, name) == 0) {
+ result = property;
+ break;
+ }
+ }
+ return result;
+}
+
+const char *
+longBowProperties_Get(const LongBowProperties *properties, const char *name)
+{
+ _Property *property = _longBowProperties_Get(properties, name);
+
+ if (property != NULL) {
+ return property->value;
+ }
+
+ return NULL;
+}
+
+bool
+longBowProperties_Set(LongBowProperties *properties, const char *name, const char *value)
+{
+ bool result = false;
+
+ _Property *property = _longBowProperties_Get(properties, name);
+ if (property == NULL) {
+ property = longBowMemory_Allocate(sizeof(_Property));
+ property->name = longBowMemory_StringCopy(name);
+ property->value = longBowMemory_StringCopy(value);
+ longBowArrayList_Add(properties->list, property);
+ result = true;
+ } else {
+ longBowMemory_Deallocate((void **) &property->value);
+ property->value = longBowMemory_StringCopy(value);
+ }
+ return result;
+}
+
+bool
+longBowProperties_Exists(const LongBowProperties *properties, const char *name)
+{
+ return (_longBowProperties_Get(properties, name) == NULL) ? false : true;
+}
+
+bool
+longBowProperties_Delete(LongBowProperties *properties, const char *name)
+{
+ bool result = false;
+
+ for (size_t index = 0; index < longBowArrayList_Length(properties->list); index++) {
+ _Property *property = longBowArrayList_Get(properties->list, index);
+ if (strcmp(property->name, name) == 0) {
+ longBowArrayList_RemoveAtIndex(properties->list, index);
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+size_t
+longBowProperties_Length(const LongBowProperties *properties)
+{
+ return longBowArrayList_Length(properties->list);
+}
+
+char *
+longBowProperties_ToString(const LongBowProperties *properties)
+{
+ LongBowString *string = longBowString_Create(128);
+
+ for (size_t index = 0; index < longBowArrayList_Length(properties->list); index++) {
+ _Property *property = longBowArrayList_Get(properties->list, index);
+ longBowString_Format(string, "%s=%s\n", property->name, property->value);
+ }
+
+ char *result = longBowString_ToString(string);
+ longBowString_Destroy(&string);
+
+ return result;
+}
+
+void
+longBowProperties_Destroy(LongBowProperties **propertiesPtr)
+{
+ LongBowProperties *properties = *propertiesPtr;
+ longBowArrayList_Destroy(&properties->list);
+ longBowMemory_Deallocate((void **) propertiesPtr);
+}
diff --git a/longbow/src/LongBow/longBow_Properties.h b/longbow/src/LongBow/longBow_Properties.h
new file mode 100755
index 00000000..493ce00e
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Properties.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 longBow_Properties.h
+ * @brief A simple properties store.
+ *
+ */
+#ifndef __LongBow__longBow_Properties__
+#define __LongBow__longBow_Properties__
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+struct LongBowProperties;
+typedef struct LongBowProperties LongBowProperties;
+
+LongBowProperties *longBowProperties_Create(void);
+
+const char *longBowProperties_Get(const LongBowProperties *properties, const char *name);
+
+size_t longBowProperties_Length(const LongBowProperties *properties);
+
+bool longBowProperties_Set(LongBowProperties *properties, const char *name, const char *value);
+
+bool longBowProperties_Exists(const LongBowProperties *properties, const char *name);
+
+bool longBowProperties_Delete(LongBowProperties *properties, const char *name);
+
+void longBowProperties_Destroy(LongBowProperties **propertiesPtr);
+
+char *longBowProperties_ToString(const LongBowProperties *properties);
+
+#endif /* defined(__LongBow__longBow_Properties__) */
diff --git a/longbow/src/LongBow/longBow_Runtime.c b/longbow/src/LongBow/longBow_Runtime.c
new file mode 100755
index 00000000..c283b743
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Runtime.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <signal.h>
+#include <errno.h>
+
+#include <LongBow/longBow_Runtime.h>
+#include <LongBow/longBow_Backtrace.h>
+#include <LongBow/longBow_Location.h>
+#include <LongBow/longBow_Event.h>
+#include <LongBow/longBow_Config.h>
+
+#include <LongBow/Reporting/longBowReport_Runtime.h>
+
+#include <LongBow/private/longBow_Memory.h>
+
+static unsigned int longBowStackTraceDepth = 128;
+
+struct longbow_runtime {
+ LongBowConfig *config;
+ LongBowRuntimeResult expectedResult;
+ LongBowRuntimeResult actualResult;
+};
+
+static LongBowRuntime longBowRuntimeGlobal;
+
+static LongBowRuntime *longBowCurrentRuntime = &longBowRuntimeGlobal;
+
+
+static char *
+_longBowRuntime_FormatErrnoMessage(void)
+{
+ char *result = NULL;
+ if (errno != 0) {
+ if (asprintf(&result, "%s: ", strerror(errno)) == -1) {
+ return NULL;
+ }
+ }
+ return result;
+}
+
+static char *
+_longBowRuntime_FormatMessage(const char *format, va_list args)
+{
+ char *errnoMessage = _longBowRuntime_FormatErrnoMessage();
+
+ char *string;
+ if (vasprintf(&string, format, args) == -1) {
+ return NULL;
+ }
+
+ char *result = NULL;
+
+ if (errnoMessage != NULL) {
+ int check = asprintf(&result, "%s%s", errnoMessage, string);
+ free(errnoMessage);
+ if (check == -1) {
+ return NULL;
+ }
+ } else {
+ result = strndup(string, strlen(string));
+ }
+
+ free(string);
+
+ return result;
+}
+
+LongBowRuntime *
+longBowRuntime_Create(const LongBowRuntimeResult *expectedResultTemplate, LongBowConfig *config)
+{
+ assert(expectedResultTemplate != NULL);
+
+ LongBowRuntime *result = longBowMemory_Allocate(sizeof(LongBowRuntime));
+ if (result != NULL) {
+ result->expectedResult = *expectedResultTemplate;
+ result->config = config;
+ }
+ return result;
+}
+
+size_t
+longBowRuntime_GetActualEventEvaluationCount(LongBowRuntime *runtime)
+{
+ return longBowRuntimeResult_GetEventEvaluationCount(longBowRuntime_GetActualTestCaseResult(runtime));
+}
+
+void
+longBowRuntime_Destroy(LongBowRuntime **runtimePtr)
+{
+ longBowMemory_Deallocate((void **) runtimePtr);
+}
+
+LongBowRuntimeResult *
+longBowRuntime_GetExpectedTestCaseResult(const LongBowRuntime *const runtime)
+{
+ return (LongBowRuntimeResult *) &(runtime->expectedResult);
+}
+
+LongBowRuntimeResult *
+longBowRuntime_GetActualTestCaseResult(const LongBowRuntime *runtime)
+{
+ return (LongBowRuntimeResult *) &(runtime->actualResult);
+}
+
+LongBowRuntime *
+longBowRuntime_SetCurrentRuntime(LongBowRuntime *runtime)
+{
+ LongBowRuntime *result = longBowCurrentRuntime;
+ longBowCurrentRuntime = runtime;
+ return result;
+}
+
+LongBowRuntime *
+longBowRuntime_GetCurrentRuntime(void)
+{
+ return longBowCurrentRuntime;
+}
+
+LongBowConfig *
+longBowRuntime_GetCurrentConfig(void)
+{
+ return longBowCurrentRuntime->config;
+}
+
+void
+longBowRuntime_SetCurrentConfig(LongBowConfig *config)
+{
+ longBowCurrentRuntime->config = config;
+}
+
+LongBowEventType *
+longBowRuntime_GetActualEventType(const LongBowRuntime *runtime)
+{
+ return runtime->actualResult.event;
+}
+
+LongBowEventType *
+longBowRuntime_GetExpectedEventType(const LongBowRuntime *runtime)
+{
+ return runtime->expectedResult.event;
+}
+
+void
+longBowRuntime_SetActualEventType(LongBowRuntime *runtime, LongBowEventType *eventType)
+{
+ runtime->actualResult.event = eventType;
+}
+
+bool
+longBowRuntime_EventEvaluation(const LongBowEventType *type)
+{
+ longBowCurrentRuntime->actualResult.eventEvaluationCount++;
+ return true;
+}
+
+unsigned int
+longBowRuntime_SetStackTraceDepth(unsigned int newDepth)
+{
+ unsigned int previousValue = longBowStackTraceDepth;
+ longBowStackTraceDepth = newDepth;
+ return previousValue;
+}
+
+unsigned int
+longBowRuntime_GetStackTraceDepth(void)
+{
+ return longBowStackTraceDepth;
+}
+
+bool
+longBowRuntime_EventTrigger(LongBowEventType *eventType, LongBowLocation *location, const char *kind, const char *format, ...)
+{
+ LongBowRuntime *runtime = longBowRuntime_GetCurrentRuntime();
+
+ longBowRuntime_SetActualEventType(runtime, eventType);
+
+ if (runtime->expectedResult.status == LONGBOW_STATUS_FAILED) {
+ return true;
+ }
+
+ if (longBowEventType_Equals(longBowRuntime_GetActualEventType(runtime), longBowRuntime_GetExpectedEventType(runtime))) {
+ return true;
+ }
+
+ va_list args;
+ va_start(args, format);
+
+ char *messageString = _longBowRuntime_FormatMessage(format, args);
+
+ va_end(args);
+
+ LongBowBacktrace *stackTrace = longBowBacktrace_Create(longBowRuntime_GetStackTraceDepth(), 2);
+
+ LongBowEvent *event = longBowEvent_Create(eventType, location, kind, messageString, stackTrace);
+
+ free(messageString);
+ longBowReportRuntime_Event(event);
+ longBowEvent_Destroy(&event);
+ return true;
+}
+
+void
+longBowRuntime_StackTrace(int fileDescriptor)
+{
+ LongBowBacktrace *backtrace = longBowBacktrace_Create(longBowRuntime_GetStackTraceDepth(), 1);
+ char *string = longBowBacktrace_ToString(backtrace);
+ fwrite(string, strlen(string), 1, stdout);
+ longBowMemory_Deallocate((void **) &string);
+ longBowBacktrace_Destroy(&backtrace);
+}
+
+bool
+longBowRuntime_TestAddressIsAligned(const void *address, size_t alignment)
+{
+ if ((alignment & (~alignment + 1)) == alignment) {
+ return (((uintptr_t) address) % alignment) == 0 ? true : false;
+ }
+ return false;
+}
+
+void
+longBowRuntime_CoreDump(void)
+{
+ struct rlimit coreDumpLimit;
+
+ coreDumpLimit.rlim_cur = RLIM_INFINITY;
+ coreDumpLimit.rlim_max = RLIM_INFINITY;
+
+ if (setrlimit(RLIMIT_CORE, &coreDumpLimit) < 0) {
+ fprintf(stderr, "setrlimit: %s\n", strerror(errno));
+ exit(1);
+ }
+ kill(0, SIGTRAP);
+}
+
+void
+longBowRuntime_Abort(void)
+{
+ bool coreDump = longBowConfig_GetBoolean(longBowRuntime_GetCurrentConfig(), false, "core-dump");
+ if (coreDump == false) {
+ abort();
+ } else {
+ longBowRuntime_CoreDump();
+ }
+}
diff --git a/longbow/src/LongBow/longBow_Runtime.h b/longbow/src/LongBow/longBow_Runtime.h
new file mode 100644
index 00000000..ff5527eb
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Runtime.h
@@ -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.
+ */
+
+/**
+ * @file longBow_Runtime.h
+ * @ingroup runtime
+ * @brief The LongBow Runtime support.
+ *
+ */
+#ifndef LongBow_longBow_Runtime_h
+#define LongBow_longBow_Runtime_h
+
+#include <LongBow/longBow_Event.h>
+#include <LongBow/longBow_RuntimeResult.h>
+#include <LongBow/longBow_Config.h>
+
+struct longbow_runtime;
+typedef struct longbow_runtime LongBowRuntime;
+
+/**
+ * Create and return a new `LongBowRuntime` instance with the specified `LongBowRuntimeResult` instance.
+ *
+ * @param [in] expectedResultTemplate A `LongBowRuntimeResult` instance.
+ *
+ * @return A pointer to an allocated LongBowRuntime instance that must be deallocated via longBowRuntime_Destroy
+ */
+LongBowRuntime *longBowRuntime_Create(const LongBowRuntimeResult *expectedResultTemplate, LongBowConfig *config);
+
+/**
+ * Destroy the `LongBowRuntime` instance.
+ *
+ * @param [in,out] runtimePtr A pointer to a `LongBowRuntime` instance.
+ */
+void longBowRuntime_Destroy(LongBowRuntime **runtimePtr);
+
+/**
+ * Get the expected test case result from the `LongBowRuntime` instance.
+ *
+ * @param [in] runtime A `LongBowRuntime` instance.
+ *
+ * @return A pointer to the expected LongBowRuntimeResult.
+ */
+LongBowRuntimeResult *longBowRuntime_GetExpectedTestCaseResult(const LongBowRuntime *runtime);
+
+/**
+ * Get the actual test case result from the `LongBowRuntime` instance.
+ *
+ * @param [in] runtime A `LongBowRuntime` instance.
+ *
+ * @return A pointer to the actual LongBowRuntimeResult.
+ */
+LongBowRuntimeResult *longBowRuntime_GetActualTestCaseResult(const LongBowRuntime *runtime);
+
+/**
+ * Get the number of events that were evalutated.
+ *
+ * @param [in] runtime A `LongBowRuntime` instance.
+ *
+ * @return The number of events that were evalutated.
+ */
+size_t longBowRuntime_GetActualEventEvaluationCount(LongBowRuntime *runtime);
+
+/**
+ * Get the LongBowEventType of the given LongBowRuntime.
+ *
+ * @param [in] runtime A `LongBowRuntime` instance.
+ *
+ * @return The LongBowEventType of the given LongBowRuntime.
+ */
+LongBowEventType *longBowRuntime_GetActualEventType(const LongBowRuntime *runtime);
+
+/**
+ * Get the expected EventType from the given LongBowRuntime.
+ *
+ * When testing, a test may set a LongBowEventType that is expected to be triggered.
+ * This function simply gets the expected LongBowEventType from the given LongBowRuntime instance.
+ *
+ * @param [in] runtime A pointer to a LongBowRuntime instance.
+ *
+ * @return The expected EventType in the LongBowRuntime.
+ */
+LongBowEventType *longBowRuntime_GetExpectedEventType(const LongBowRuntime *runtime);
+
+/**
+ * Set the "actual" LongBowEventType of the given LongBowRuntime.
+ *
+ * @param [in] runtime A `LongBowRuntime` instance.
+ * @param [in] eventType A `LongBowEventType` instance.
+ */
+void longBowRuntime_SetActualEventType(LongBowRuntime *runtime, LongBowEventType *eventType);
+
+/**
+ * Set the current `LongBowRuntime`.
+ *
+ * @param [in] runtime A `LongBowRuntime` instance.
+ *
+ * @return The previous LongBowRuntime
+ */
+LongBowRuntime *longBowRuntime_SetCurrentRuntime(LongBowRuntime *runtime);
+
+/**
+ * Retrieve the current `LongBowRuntime`.
+ *
+ * @return The current global LongBowRuntime.
+ */
+LongBowRuntime *longBowRuntime_GetCurrentRuntime(void);
+
+/**
+ * Retrieve the `LongBowConfig` instance of the current global runtime.
+ *
+ * @return The `LongBowConfig` instance of the current global runtime.
+ */
+LongBowConfig *longBowRuntime_GetCurrentConfig(void);
+
+/**
+ * Set the `LongBowConfig` instance of the current global runtime.
+ *
+ * @param [in] config The new `LongBowConfig` instance of the current global runtime.
+ */
+void longBowRuntime_SetCurrentConfig(LongBowConfig *config);
+
+/**
+ * Trigger a LongBow event.
+ *
+ * The event will be reported via the longBowReport_Event.
+ *
+ * @param [in] eventType The type of event.
+ * @param [in] location The LongBowLocation of the event (this will be destroyed).
+ * @param [in] kind A string indicating the kind of event this is triggering.
+ * @param [in] format A printf format string.
+ * @param [in] ... Parameters associated with the printf format string.
+ *
+ * @return true Always return true.
+ */
+bool longBowRuntime_EventTrigger(LongBowEventType *eventType,
+ LongBowLocation *location,
+ const char *kind,
+ const char *format, ...) __attribute__((__format__(__printf__, 4, 5)));
+/**
+ * Record an event evaluation.
+ *
+ * This only records the fact of the evaluation, not the results of the evaluation.
+ *
+ * @param [in] type A pointer to the LongBowEventType being evaluated.
+ *
+ * @return true Always returns true.
+ *
+ * Example:
+ * @code
+ * {
+ * longBowRuntime_EventEvaluation(&LongBowAssertEvent);
+ * }
+ * @endcode
+ */
+bool longBowRuntime_EventEvaluation(const LongBowEventType *type);
+
+/**
+ * Set the current value for the depth of printed stack trace.
+ *
+ * If the depth is less than 1, no stack trace is displayed.
+ *
+ * @param [in] newDepth The new value to set.
+ *
+ * @return The previous value.
+ */
+unsigned int longBowRuntime_SetStackTraceDepth(unsigned int newDepth);
+
+/**
+ * Get the current value for the depth of printed stack trace.
+ *
+ * @return The current stack-trace depth.
+ */
+unsigned int longBowRuntime_GetStackTraceDepth(void);
+
+/**
+ * Print a formatted stack trace to the current output file descriptor.
+ *
+ * @param [in] fileDescriptor A valid file descriptor.
+ */
+void longBowRuntime_StackTrace(int fileDescriptor);
+
+/**
+ * Abort the running process using the current runtime environment.
+ * If the configuration is set to produce a core dump, this function simply returns.
+ * This permits the caller to use the form:
+ * <code>
+ * longBowRuntime_Abort(), kill(0, SIGTRACE)
+ * </code>
+ * To generate a core image.
+ *
+ * See the assertion macros for how this is used.
+ */
+void longBowRuntime_Abort(void);
+#endif // LongBow_longBow_Runtime_h
diff --git a/longbow/src/LongBow/longBow_RuntimeResult.c b/longbow/src/LongBow/longBow_RuntimeResult.c
new file mode 100755
index 00000000..f91dfe1e
--- /dev/null
+++ b/longbow/src/LongBow/longBow_RuntimeResult.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 <sys/time.h>
+
+#include <LongBow/longBow_RuntimeResult.h>
+
+size_t
+longBowRuntimeResult_GetEventEvaluationCount(const LongBowRuntimeResult *testCaseResult)
+{
+ return testCaseResult->eventEvaluationCount;
+}
+
+LongBowEventType *
+longBowRuntimeResult_GetEvent(const LongBowRuntimeResult *testCaseResult)
+{
+ return testCaseResult->event;
+}
+
+void
+longBowRuntimeResult_SetEvent(LongBowRuntimeResult *testCaseResult, LongBowEventType *eventType)
+{
+ testCaseResult->event = eventType;
+}
+
+void
+longBowRuntimeResult_SetStatus(LongBowRuntimeResult *testCaseResult, LongBowStatus status)
+{
+ testCaseResult->status = status;
+}
+void
+longBowRuntimeResult_SetElapsedTime(LongBowRuntimeResult *testCaseResult, struct timeval *elapsedTime)
+{
+ testCaseResult->elapsedTime = *elapsedTime;
+}
+
+struct rusage *
+longBowRuntimeResult_GetRUsage(LongBowRuntimeResult *testCaseResult)
+{
+ return &testCaseResult->resources;
+}
+
+void
+longBowRuntimeResult_SetRUsage(LongBowRuntimeResult *testCaseResult, struct rusage *resources)
+{
+ testCaseResult->resources = *resources;
+}
+
+LongBowStatus
+longBowRuntimeResult_GetStatus(const LongBowRuntimeResult *testCaseResult)
+{
+ return testCaseResult->status;
+}
+
+struct timeval
+longBowRuntimeResult_GetElapsedTime(const LongBowRuntimeResult *testCaseResult)
+{
+ return testCaseResult->elapsedTime;
+}
diff --git a/longbow/src/LongBow/longBow_RuntimeResult.h b/longbow/src/LongBow/longBow_RuntimeResult.h
new file mode 100755
index 00000000..367ad1ae
--- /dev/null
+++ b/longbow/src/LongBow/longBow_RuntimeResult.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 longBow_RuntimeResult.h
+ * @ingroup internals
+ * @brief LongBow Test Case Results
+ *
+ * LongBow Test Cases have expected and actual results.
+ * The expected results are typically a statically created instance of {@link LongBowRuntimeResult}
+ * which is used when the Test Case is executed to compare with the actual results.
+ * This permits, for example, a Test Case to indicate that it is expected to induce a specific LongBowEvent.
+ * In which case, the actual LongBowEvent must equal the expected event for the Test Case to be considered a success.
+ *
+ */
+#ifndef LongBow_longBow_CaseResult_h
+#define LongBow_longBow_CaseResult_h
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/resource.h>
+
+#include <LongBow/longBow_Status.h>
+#include <LongBow/longBow_Event.h>
+
+struct longbow_testcase_result;
+
+/**
+ * @typedef LongBowRuntimeResult
+ * @brief The expected and actual result of a LongBow Test.
+ */
+typedef struct longbow_testcase_result LongBowRuntimeResult;
+
+/**
+ * @struct longbow_testcase_result
+ * @brief The expected and actual result of a LongBow Test.
+ */
+struct longbow_testcase_result {
+ /**
+ * The number of event evaluations performed.
+ * These asserts and traps with conditions that were evaluated.
+ */
+ size_t eventEvaluationCount;
+ LongBowStatus status; /**< The resulting status of the test case. */
+ struct timeval elapsedTime; /**< The elapsed time of the test case. */
+ struct rusage resources; /**< The resulting resource usage of the test case. */
+ LongBowEventType *event; /**< The expected or actual event. */
+};
+
+/**
+ * Return the event evaluation count associated with the given `LongBowRuntimeResult` instance.
+ *
+ * @param [in] testCaseResult A `LongBowRuntimeResult` instance.
+ *
+ * @return The number of Event evaluations.
+ */
+size_t longBowRuntimeResult_GetEventEvaluationCount(const LongBowRuntimeResult *testCaseResult);
+
+/**
+ * Retrieve the event type associated with the given `LongBowRuntimeResult` instance.
+ *
+ * @param [in] testCaseResult A `LongBowRuntimeResult` instance.
+ *
+ * @return The LongBowEventType for the given LongBowRuntimeResult.
+ */
+LongBowEventType *longBowRuntimeResult_GetEvent(const LongBowRuntimeResult *testCaseResult);
+
+/**
+ * Set the event type associated with the given `LongBowRuntimeResult` instance.
+ *
+ * @param [in] testCaseResult A `LongBowRuntimeResult` instance.
+ * @param [in] eventType A new `LongBowEventType` instance.
+ */
+void longBowRuntimeResult_SetEvent(LongBowRuntimeResult *testCaseResult, LongBowEventType *eventType);
+
+/**
+ * Get the LongBowStatus type from the given `LongBowRuntimeResult` instance.
+ *
+ * @param [in] testCaseResult A `LongBowRuntimeResult` instance.
+ *
+ * @return The LongBowStatus of the given LongBowRuntimeResult.
+ */
+LongBowStatus longBowRuntimeResult_GetStatus(const LongBowRuntimeResult *testCaseResult);
+
+/**
+ * Set the LongBowStatus type for the given `LongBowRuntimeResult` instance.
+ *
+ * @param [in] testCaseResult A `LongBowRuntimeResult` instance.
+ * @param [in] status A `LongBowStatus` value.
+ */
+void longBowRuntimeResult_SetStatus(LongBowRuntimeResult *testCaseResult, LongBowStatus status);
+
+/**
+ * Set the elapsed time for the given `LongBowRuntimeResult` instance.
+ *
+ * @param [in] testCaseResult A `LongBowRuntimeResult` instance.
+ * @param [in] elapsedTime A `struct timeval` instance.
+ */
+void longBowRuntimeResult_SetElapsedTime(LongBowRuntimeResult *testCaseResult, struct timeval *elapsedTime);
+
+/**
+ * Get the elapsed time associated with the given `LongBowRuntimeResult` instance.
+ *
+ * @param [in] testCaseResult A `LongBowRuntimeResult` instance.
+ *
+ * @return A copy of the timeval of the given LongBowRuntimeResult.
+ */
+struct timeval longBowRuntimeResult_GetElapsedTime(const LongBowRuntimeResult *testCaseResult);
+
+/**
+ * Retrieve the RUsage struct from the given `LongBowRuntimeResult` instance.
+ *
+ * @param [in] testCaseResult A `LongBowRuntimeResult` instance.
+ *
+ * @return A pointer to the struct rusage instance in the given LongBowRuntimeResult.
+ */
+struct rusage *longBowRuntimeResult_GetRUsage(LongBowRuntimeResult *testCaseResult);
+
+/**
+ * Set the RUsage struct for the given `LongBowRuntimeResult` instance.
+ *
+ * @param [in] testCaseResult A `LongBowRuntimeResult` instance.
+ * @param [in] rusage A `struct rusage` instance.
+ */
+void longBowRuntimeResult_SetRUsage(LongBowRuntimeResult *testCaseResult, struct rusage *rusage);
+#endif
diff --git a/longbow/src/LongBow/longBow_Status.c b/longbow/src/LongBow/longBow_Status.c
new file mode 100644
index 00000000..200a2aea
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Status.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/longBow_Status.h>
+#include <LongBow/unit-test.h>
+
+bool
+longBowStatus_IsSuccessful(LongBowStatus status)
+{
+ if (status == LONGBOW_STATUS_SUCCEEDED || longBowStatus_IsWarning(status) || longBowStatus_IsIncomplete(status)) {
+ return true;
+ }
+ return false;
+}
+
+bool
+longBowStatus_IsFailed(LongBowStatus status)
+{
+ switch (status) {
+ case LONGBOW_STATUS_FAILED:
+ case LONGBOW_STATUS_MEMORYLEAK:
+ case LongBowStatus_STOPPED:
+ case LONGBOW_STATUS_TEARDOWN_FAILED:
+ case LONGBOW_STATUS_SETUP_FAILED:
+ return true;
+
+ default:
+ if (status >= LongBowStatus_SIGNALLED) {
+ return true;
+ }
+ return false;
+ }
+}
+
+bool
+longBowStatus_IsWarning(LongBowStatus status)
+{
+ switch (status) {
+ case LongBowStatus_WARNED:
+ case LongBowStatus_TEARDOWN_WARNED:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool
+longBowStatus_IsIncomplete(LongBowStatus status)
+{
+ switch (status) {
+ case LONGBOW_STATUS_SKIPPED:
+ case LongBowStatus_UNIMPLEMENTED:
+ case LongBowStatus_IMPOTENT:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool
+longBowStatus_IsSignalled(LongBowStatus status)
+{
+ return status >= LongBowStatus_SIGNALLED;
+}
+
+static struct toString {
+ LongBowStatus status;
+ char *string;
+} toString[] = {
+ { LONGBOW_STATUS_SUCCEEDED, "Succeeded" },
+ { LongBowStatus_WARNED, "Warning" },
+ { LongBowStatus_TEARDOWN_WARNED, "Tear Down Warning" },
+ { LONGBOW_STATUS_SKIPPED, "Skipped" },
+ { LongBowStatus_UNIMPLEMENTED, "Unimplemented" },
+ { LongBowStatus_IMPOTENT, "Impotent" },
+ { LONGBOW_STATUS_FAILED, "Failed" },
+ { LongBowStatus_STOPPED, "Stopped" },
+ { LONGBOW_STATUS_TEARDOWN_FAILED, "Tear Down Failed" },
+ { LONGBOW_STATUS_SETUP_FAILED, "Setup Failed" },
+ { LONGBOW_STATUS_MEMORYLEAK, "Memory Leak" },
+ { 0, NULL },
+};
+
+static const char *
+_longBowStatus_StatusToString(const LongBowStatus status)
+{
+ const char *result = NULL;
+ for (const struct toString *element = &toString[0]; element->string != NULL; element++) {
+ if (element->status == status) {
+ result = element->string;
+ break;
+ }
+ }
+ return result;
+}
+
+char *
+longBowStatus_ToString(const LongBowStatus status)
+{
+ char *result = (char *) _longBowStatus_StatusToString(status);
+
+ if (result == NULL) {
+ if (status >= LongBowStatus_SIGNALLED) {
+ int signalNumber = status - LongBowStatus_SIGNALLED;
+ char *signalName = strsignal(signalNumber);
+ int check;
+ if (signalName == NULL) {
+ check = asprintf(&result, "Signaled %d.", signalNumber);
+ } else {
+ check = asprintf(&result, "Signaled %s.", signalName);
+ }
+ if (check == -1) {
+ return NULL;
+ }
+ } else {
+ int check = asprintf(&result, "Unknown status: %d. This is a bug.", status);
+ if (check == -1) {
+ return NULL;
+ }
+ }
+ } else {
+ result = strdup(result);
+ }
+
+ return result;
+}
diff --git a/longbow/src/LongBow/longBow_Status.h b/longbow/src/LongBow/longBow_Status.h
new file mode 100755
index 00000000..de45ae6d
--- /dev/null
+++ b/longbow/src/LongBow/longBow_Status.h
@@ -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.
+ */
+
+/**
+ * @file longBow_Status.h
+ * @ingroup testing
+ * @brief A simple status representation for a LongBow Test Case.
+ *
+ */
+#ifndef LongBow_longBow_Status_h
+#define LongBow_longBow_Status_h
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/**
+ * @typedef LongBowStatus
+ * @brief The status of an individual Test Case, and aggregate Test Fixture, or Test Runner.
+ *
+ * Status is either successful or not and each has a subset of qualifiers.
+ *
+ * A successful status is an outright success, or a qualified success.
+ *
+ * Qualified success is a test that issued an explicit warning (via <code>testWarn(...)</code>),
+ * was purposefully skipped (via <code>testSkip(...)</code>),
+ * or is unimplemented (via <code>testUnimplemented(...)</code>).
+ *
+ * Correspondingly, an unsuccessful test is outright failure,
+ * or a qualified failure.
+ * Qualified values indicate that the test process received a signal during the test,
+ * or either the Test Fixture set-up or tear-down steps signaled failure.
+ *
+ */
+enum LongBowStatus {
+ /**
+ * Used for expressing the expected status.
+ */
+ LongBowStatus_DONTCARE = -2,
+
+ /**
+ * The test was not run (initial state).
+ */
+ LongBowStatus_UNTESTED = -1,
+
+ /* successful */
+ /**
+ * The test was successful.
+ */
+ LONGBOW_STATUS_SUCCEEDED = 0,
+ /**
+ * The test was successful, but with a warning.
+ */
+
+ LongBowStatus_WARNED = 10,
+ /**
+ * The test was successful, but the tear down issued a warning.
+ */
+
+ LongBowStatus_TEARDOWN_WARNED = 11,
+
+ /**
+ * The test was purposefully skipped by the test implementor.
+ */
+ LONGBOW_STATUS_SKIPPED = 21,
+
+ /**
+ * The test was incomplete because it signals that it is not implemented.
+ */
+ LongBowStatus_UNIMPLEMENTED = 22,
+
+ /**
+ * The test ran but evaluated nothing.
+ */
+ LongBowStatus_IMPOTENT = 23,
+
+ /**
+ * The setup function signals that all of the subordinate test cases must be skipped.
+ */
+ LONGBOW_STATUS_SETUP_SKIPTESTS = 24,
+
+ /* failures */
+ /**
+ * The tests failed.
+ */
+ LONGBOW_STATUS_FAILED = 1,
+
+ /**
+ * The test failed because it was stopped by a signal.
+ */
+ LongBowStatus_STOPPED = 3,
+
+ /**
+ * The tear down of the test failed.
+ *
+ * This doesn't imply that the test failed.
+ */
+ LONGBOW_STATUS_TEARDOWN_FAILED = 4,
+
+ /**
+ * The test was incomplete because the setup for the test failed.
+ */
+ LONGBOW_STATUS_SETUP_FAILED = 5,
+
+ /**
+ * The test was incomplete because a memory leak was detected.
+ */
+ LONGBOW_STATUS_MEMORYLEAK = 6,
+
+ /**
+ * The test failed due to an uncaught signal.
+ */
+ LongBowStatus_SIGNALLED = 100,
+
+ /**
+ * The limit of LongBowStatus values
+ */
+ LongBowStatus_LIMIT = 200,
+};
+typedef enum LongBowStatus LongBowStatus;
+
+/**
+ * Compose a LongBowStatus from the given signalNumber.
+ */
+#define LongBowStatus_SIGNAL(signalNumber) (LongBowStatus_SIGNALLED + signalNumber)
+
+/**
+ * Generate a human readable, nul-terminated C string representation of the `LongBowStatus` value.
+ *
+ * @param [in] status A `LongBowStatus` value
+ *
+ * @return A pointer to an allocated C string that must be freed via stdlib.h free(3).
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowStatus status = LONGBOW_STATUS_SUCCEEDED;
+ * printf("Status = %s\n", longBowStatus_ToString(status));
+ * }
+ * @endcode
+ */
+char *longBowStatus_ToString(LongBowStatus status);
+
+/**
+ * Return `true` if the given status indicates an outright or qualified success.
+ *
+ * Success, outright or qualified, encompasses `LONGBOW_STATUS_SUCCEEDED`,
+ * longBowStatus_IsWarning(status), or
+ * longBowStatus_IsIncomplete(status)
+ *
+ * @param [in] status A `LongBowStatus` value.
+ *
+ * @return `true` if the given status indicated an outright or qualified success.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowStatus status = LONGBOW_STATUS_SUCCEEDED;
+ * printf("Is success? = %d\n", longBowStatus_IsSuccessful(status));
+ * }
+ * @endcode
+ */
+bool longBowStatus_IsSuccessful(LongBowStatus status);
+
+/**
+ * Return <code>true</code> if the given status indicates a failure.
+ *
+ * @param [in] status A `LongBowStatus` value.
+ *
+ * @return `true` if the given status indicated a failure.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowStatus status = LONGBOW_STATUS_FAILED;
+ * printf("Is warned? = %d\n", longBowStatus_IsFailed(status));
+ * }
+ * @endcode
+ */
+bool longBowStatus_IsFailed(LongBowStatus status);
+
+/**
+ * Return <code>true</code> if the given status indicates a warning.
+ *
+ * @param [in] status A `LongBowStatus` value.
+ *
+ * @return Return `true` if the given status indicate a warning.
+ */
+bool longBowStatus_IsWarning(LongBowStatus status);
+
+/**
+ * Return <code>true</code> if the given status indicates a test was incomplete.
+ *
+ * @param [in] status A `LongBowStatus` value.
+ *
+ * @return `true` if the given status indicated it was incomplete.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowStatus status = LONGBOW_STATUS_SKIPPED;
+ * printf("Is incomplete? = %d\n", longBowStatus_IsIncomplete(status));
+ * }
+ * @endcode
+ */
+bool longBowStatus_IsIncomplete(LongBowStatus status);
+
+/**
+ * Return <code>true</code> if the given status indicated a test induced a signal.
+ *
+ * @param [in] status A `LongBowStatus` value.
+ *
+ * @return `true` if the given status indicated a test induced a signal.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowStatus status = LongBowStatus_SIGNALLED;
+ * printf("Is signalled? = %d\n", longBowStatus_IsSignalled(status));
+ * }
+ * @endcode
+ */
+bool longBowStatus_IsSignalled(LongBowStatus status);
+#endif // LONGBOWSTATUS_H_
diff --git a/longbow/src/LongBow/longBow_SubProcess.c b/longbow/src/LongBow/longBow_SubProcess.c
new file mode 100755
index 00000000..2bd91dd5
--- /dev/null
+++ b/longbow/src/LongBow/longBow_SubProcess.c
@@ -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.
+ */
+
+/**
+ */
+#include <config.h>
+
+# include "longBow_SubProcess_Darwin_x86_64.c"
diff --git a/longbow/src/LongBow/longBow_SubProcess.h b/longbow/src/LongBow/longBow_SubProcess.h
new file mode 100755
index 00000000..83aac8c8
--- /dev/null
+++ b/longbow/src/LongBow/longBow_SubProcess.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 longBow_SubProcess.h
+ * @ingroup testing
+ * @brief Facilities for running and managing subprocesses.
+ *
+ */
+#ifndef LongBow_longBow_SubProcess_h
+#define LongBow_longBow_SubProcess_h
+
+#include <stdbool.h>
+
+struct longbow_subprocess;
+typedef struct longbow_subprocess LongBowSubProcess;
+
+/**
+ * Start a subprocess.
+ *
+ * @param [in] path The pathname, either absolute or relative to the current directory, of the program to execute.
+ * @param [in] ... A NULL terminated parameter list consisting of the parameters of the executable starting at `argv[0]`.
+ *
+ * @return A pointer to a `LongBowSubProcess` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowSubProcess *process = longBowSubProcess_Exec("/bin/pwd", "pwd", NULL);
+ * }
+ * @endcode
+ *
+ * @see longBowSubProcess_Wait
+ * @see longBowSubProcess_Signal
+ * @see longBowSubProcess_Terminate
+ * @see longBowSubProcess_Wait
+ */
+LongBowSubProcess *longBowSubProcess_Exec(const char *path, ... /*, (char *)0 */);
+
+/**
+ * Destroy a `LongBowSubProcess`
+ *
+ * If the process is still running it is sent the SIGKILL signal.
+ *
+ * @param [in] subProcessPtr A pointer to a `LongBowSubProcess` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowSubProcess *process = longBowSubProcess_Exec("/bin/pwd", "pwd", NULL);
+ *
+ * longBowSubProcess_Destroy(&process);
+ * }
+ * @endcode
+ *
+ * @see longBowSubProcess_Exec
+ */
+void longBowSubProcess_Destroy(LongBowSubProcess **subProcessPtr);
+
+/**
+ * Send a signal to a LongBowSubProcess
+ *
+ * @param [in] subProcess The LongBowSubProcess to receive the signal.
+ * @param [in] signalNumber The signal to send.
+ *
+ * @return true The signal was successfully sent.
+ * @return false The signal was not successfully sent.
+ *
+ * Example:
+ * @code
+ * {
+ * longBowSubProcess_Signal(subProcess, SIGTERM);
+ * }
+ * @endcode
+ *
+ * @see longBowSubProcess_Terminate
+ */
+bool longBowSubProcess_Signal(LongBowSubProcess *subProcess, int signalNumber);
+
+/**
+ * Send a SIGTERM to a LongBowSubProcess
+ *
+ * @param [in] subProcess The LongBowSubProcess to receive the signal.
+ *
+ * @return true The signal was successfully sent.
+ * @return false The signal was not successfully sent.
+ *
+ * Example:
+ * @code
+ * {
+ * longBowSubProcess_Signal(subProcess, SIGTERM);
+ * }
+ * @endcode
+ *
+ * @see longBowSubProcess_Terminate
+ */
+bool longBowSubProcess_Terminate(LongBowSubProcess *subProcess);
+
+/**
+ * Wait for a `LongBowSubProcess` to stop or terminate
+ *
+ * @param [in] subProcess The LongBowSubProcess to wait for.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ */
+void longBowSubProcess_Wait(LongBowSubProcess *subProcess);
+
+/**
+ * Print a human readable representation of the given `LongBowSubProcess`.
+ *
+ * @param [in] indentation The level of indentation to use to pretty-print the output.
+ * @param [in] subprocess A pointer to the instance to display.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowSubProcess *process = longBowSubProcess_Exec("/bin/pwd", "pwd", NULL);
+ *
+ * longBowSubProcess_Display(process, 0);
+ *
+ * longBowSubProcess_Destroy(&process);
+ * }
+ * @endcode
+ *
+ */
+void longBowSubProcess_Display(const LongBowSubProcess *subprocess, int indentation);
+#endif
diff --git a/longbow/src/LongBow/longBow_SubProcess_Darwin_x86_64.c b/longbow/src/LongBow/longBow_SubProcess_Darwin_x86_64.c
new file mode 100755
index 00000000..6c0a0f7a
--- /dev/null
+++ b/longbow/src/LongBow/longBow_SubProcess_Darwin_x86_64.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 <stdio.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include <LongBow/longBow_SubProcess.h>
+#include <LongBow/private/longBow_Memory.h>
+
+struct longbow_subprocess {
+ const char *path;
+ char **arguments;
+ pid_t pid;
+ int exitStatus;
+ struct rusage rusage;
+};
+
+static void
+_resetAllSignals(void)
+{
+ struct sigaction signalAction;
+ signalAction.sa_handler = SIG_DFL;
+ signalAction.sa_flags = SA_SIGINFO;
+ sigemptyset(&signalAction.sa_mask);
+
+ for (int i = 1; i < NSIG; i++) {
+ sigaction(i, &signalAction, NULL);
+ }
+}
+
+LongBowSubProcess *
+longBowSubProcess_Exec(const char *path, ... /*, (char *)0 */)
+{
+ va_list ap;
+ va_start(ap, path);
+
+ size_t count = 0;
+ for (char *arg = va_arg(ap, char *); arg != NULL; arg = va_arg(ap, char *)) {
+ count++;
+ }
+
+ LongBowSubProcess *result = longBowMemory_Allocate(sizeof(LongBowSubProcess));
+
+ result->path = path;
+ longBowMemory_Allocate(sizeof(char *) * count + 1);
+ va_end(ap);
+ // This relies on the last element being all zeros.
+ va_start(ap, path);
+
+ for (size_t i = 0; i < count; i++) {
+ result->arguments[i] = va_arg(ap, char *);
+ }
+ va_end(ap);
+
+ result->pid = fork();
+ if (result->pid == 0) {
+ _resetAllSignals();
+ printf("Exec %s\n", result->path);
+ int error = execv(result->path, result->arguments);
+ printf("Error %d\n", error);
+ perror(path);
+ exit(1);
+ }
+
+ printf("Process group child=%d, parent=%d\n", getpgid(result->pid), getpgrp());
+ return result;
+}
+
+void
+longBowSubProcess_Destroy(LongBowSubProcess **processPtr)
+{
+ LongBowSubProcess *process = *processPtr;
+
+ if (process->pid) {
+ longBowSubProcess_Signal(process, SIGKILL);
+ }
+
+ longBowMemory_Deallocate((void **) process->arguments);
+ longBowMemory_Deallocate((void **) processPtr);
+}
+
+bool
+longBowSubProcess_Terminate(LongBowSubProcess *subProcess)
+{
+ return longBowSubProcess_Signal(subProcess, SIGTERM);
+}
+
+bool
+longBowSubProcess_Signal(LongBowSubProcess *subProcess, int signalNumber)
+{
+ return kill(subProcess->pid, signalNumber) == 0;
+}
+
+void
+longBowSubProcess_Wait(LongBowSubProcess *subProcess)
+{
+ wait4(subProcess->pid, &subProcess->exitStatus, 0, &subProcess->rusage);
+ subProcess->pid = 0;
+}
+
+void
+longBowSubProcess_Display(const LongBowSubProcess *subprocess, int indentation)
+{
+ printf("%*s%s: ", indentation, "", subprocess->path);
+ if (subprocess->pid == 0) {
+ printf("not running .exitStatus=%d ", subprocess->exitStatus);
+ } else {
+ printf(".pid=%d", subprocess->pid);
+ }
+
+ printf("\n");
+}
diff --git a/longbow/src/LongBow/longBow_TestCase.c b/longbow/src/LongBow/longBow_TestCase.c
new file mode 100644
index 00000000..3b487905
--- /dev/null
+++ b/longbow/src/LongBow/longBow_TestCase.c
@@ -0,0 +1,643 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <setjmp.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <LongBow/unit-test.h>
+
+#include <LongBow/Reporting/longBowReport_Testing.h>
+
+#include <LongBow/longBow_Config.h>
+#include <LongBow/longBow_TestCaseClipBoard.h>
+#include <LongBow/private/longBow_Memory.h>
+#include <LongBow/private/longBow_String.h>
+
+
+/**
+ * @struct longbow_testcase
+ * @brief The specification of a LongBow Test Case.
+ *
+ */
+struct longbow_testcase {
+ /**
+ * The name of the test case as a C string.
+ */
+ const char *testCaseName;
+
+ const LongBowTestCaseMetaData *metaData;
+
+ char *fullName;
+
+ /**
+ * The fixture that is running this test case.
+ */
+ const LongBowTestFixture *fixture;
+
+ /**
+ * The function to execute the test case.
+ */
+ LongBowTestCaseFunction *testCase;
+
+ /**
+ * The runtime characteristics consisting of the expected and actual results.
+ */
+ LongBowRuntime *runtime;
+};
+
+
+void
+longBowTestCase_ConfigHelp(void)
+{
+ printf("Test Case options:\n");
+ printf(" --set <runnerName>/<fixtureName>/iterations=<integer> Run the named test case <integer> times.\n");
+}
+
+LongBowTestCase *
+longBowTestCase_Create(const char *testCaseName,
+ const LongBowTestFixture *testFixture,
+ LongBowTestCaseFunction *testCase,
+ const LongBowTestCaseMetaData *metaData)
+{
+ assert(testCaseName != NULL);
+
+ LongBowTestCase *result = longBowMemory_Allocate(sizeof(LongBowTestCase));
+ if (result != NULL) {
+ result->testCaseName = testCaseName;
+ int status = asprintf(&result->fullName, "%s/%s", longBowTestFixture_GetFullName(testFixture), testCaseName);
+ assert(status != -1);
+ result->fixture = testFixture;
+ result->testCase = testCase;
+ result->runtime = longBowRuntime_Create(&metaData->expectedResult,
+ longBowTestRunner_GetConfiguration(longBowTestFixture_GetRunner(testFixture)));
+ result->metaData = metaData;
+ }
+ return result;
+}
+
+const char *
+longBowTestCase_GetFullName(const LongBowTestCase *testCase)
+{
+ assert(testCase != NULL);
+ return testCase->fullName;
+}
+
+void
+longBowTestCase_Destroy(LongBowTestCase **testCaseP)
+{
+ LongBowTestCase *testCase = *testCaseP;
+
+ longBowRuntime_Destroy(&(testCase->runtime));
+
+ longBowMemory_Deallocate((void **) testCaseP);
+}
+
+/*
+ * Given the exit status of a test as returned by wait(2), return the corresponding {@link LongBowStatus}.
+ *
+ * @param [in] waitStatus
+ * @return LongBowStatus
+ */
+static LongBowStatus
+_longBowTestCase_ParseWaitStatus(int waitStatus)
+{
+ LongBowStatus result = LongBowStatus_WARNED;
+ if (WIFSIGNALED(waitStatus)) {
+ int exitSignal = WTERMSIG(waitStatus);
+ if (exitSignal == SIGABRT) {
+ result = LONGBOW_STATUS_FAILED;
+ } else {
+ result = LongBowStatus_SIGNALLED + exitSignal;
+ }
+ } else if (WIFEXITED(waitStatus)) {
+ result = (LongBowStatus) WEXITSTATUS(waitStatus);
+ } else {
+ result = LongBowStatus_STOPPED;
+ }
+
+ return result;
+}
+
+LongBowLocation *
+longBowTestCase_CreateLocation(const LongBowTestCase *testCase)
+{
+ LongBowLocation *result = longBowLocation_Create(testCase->metaData->fileName, testCase->fullName, testCase->metaData->lineNumber);
+ return result;
+}
+
+const char *
+longBowTestCase_GetName(const LongBowTestCase *testCase)
+{
+ return testCase->testCaseName;
+}
+
+LongBowTestFixture *
+longBowTestCase_GetFixture(const LongBowTestCase *testCase)
+{
+ return (LongBowTestFixture *) testCase->fixture;
+}
+
+LongBowRuntimeResult *
+longBowTestCase_GetExpectedResult(const LongBowTestCase *testCase)
+{
+ return longBowRuntime_GetExpectedTestCaseResult(testCase->runtime);
+}
+
+LongBowRuntimeResult *
+longBowTestCase_GetActualResult(const LongBowTestCase *testCase)
+{
+ return longBowRuntime_GetActualTestCaseResult(testCase->runtime);
+}
+
+size_t
+longBowTestCase_GetEventEvaluationCount(const LongBowTestCase *testCase)
+{
+ return longBowRuntime_GetActualEventEvaluationCount(testCase->runtime);
+}
+
+static jmp_buf longBowTestCaseAbort;
+
+/*
+ * The process running the Test Case receives a signal.
+ *
+ * A regular, passing Test Case induces no signal and as a result does not pass through this function.
+ * A Test Case that fails an assertion will induce the SIGABRT signal which does pass through this function.
+ * Any other signal is because the Test Case either purposefully sent itself a signal, (including calling abort()),
+ * or it induced one through some implicit behaviour (like a SIGSEGV).
+ *
+ * In all remaining cases, encode the signal received into a return value for the
+ * corresponding setjmp() and invoke the longjmp().
+ */
+__attribute__((noreturn))
+static void
+_longBowTestCase_ReceiveSignal(int signal, siginfo_t *siginfo __attribute__((unused)), void *data __attribute__((unused)))
+{
+ if (signal == SIGINT) {
+ printf("Howdy\n");
+ }
+ longjmp(longBowTestCaseAbort, signal);
+}
+
+/**
+ * Return true or false, if LongBow should capture a signal, or not.
+ *
+ * LongBow captures signals in order to report on the success or failure of a test.
+ * Some signals do not indicate that a test failed,
+ * only that the environment changed,
+ * or some other event that is unrelated to success or failure.
+ * Unless, of course, the test is checking for the event (this is not yet supported).
+ */
+static bool
+_longBowTestCase_MustCaptureSignal(const int signal)
+{
+ switch (signal) {
+ case SIGTRAP:
+ return false;
+
+ case SIGCHLD:
+ return false;
+
+ case SIGKILL:
+ return false;
+
+ case SIGSTOP:
+ return false;
+
+ case SIGWINCH:
+ return false;
+
+ default:
+ return true;
+ }
+}
+
+/**
+ * Setup signals to point to the testCaseSignalAction handler for all signals possible.
+ */
+static void
+_longBowTestCase_TestInitSignals(void)
+{
+ struct sigaction signalAction;
+ signalAction.sa_sigaction = _longBowTestCase_ReceiveSignal;
+ signalAction.sa_flags = SA_SIGINFO;
+ sigemptyset(&signalAction.sa_mask);
+
+ struct sigaction oldSignals[NSIG];
+ for (int i = 1; i < NSIG; i++) {
+ if (_longBowTestCase_MustCaptureSignal(i)) {
+ sigaction(i, &signalAction, &oldSignals[i]);
+ }
+ }
+}
+
+/**
+ * Setup signals to their default behaviour.
+ */
+static void
+_longBowTestCase_TestFiniSignals(void)
+{
+ struct sigaction signalAction;
+ signalAction.sa_handler = SIG_DFL;
+ signalAction.sa_flags = SA_SIGINFO;
+ sigemptyset(&signalAction.sa_mask);
+
+ for (int i = 1; i < NSIG; i++) {
+ if (_longBowTestCase_MustCaptureSignal(i)) {
+ sigaction(i, &signalAction, NULL);
+ }
+ }
+}
+
+/*
+ * Determine the status of the given LongBowTestCase.
+ *
+ * If the actual event recorded in the test case is equal to the expected event,
+ * then return LONGBOW_STATUS_SUCCEEDED.
+ * If the actual event is NULL and the expected event is not, then return LONGBOW_STATUS_FAILED.
+ * Otherwise, the result is the actual event.
+ */
+static LongBowStatus
+_longBowTestCase_ExpectedVsActualEvent(const LongBowTestCase *testCase)
+{
+ LongBowStatus result = LONGBOW_STATUS_FAILED;
+ LongBowEventType *expectedEvent = longBowRuntimeResult_GetEvent(longBowTestCase_GetExpectedResult(testCase));
+ LongBowEventType *actualEvent = longBowRuntimeResult_GetEvent(longBowTestCase_GetActualResult(testCase));
+
+ if (longBowEventType_Equals(expectedEvent, actualEvent)) {
+ result = LONGBOW_STATUS_SUCCEEDED;
+ } else if (actualEvent == NULL && expectedEvent != NULL) {
+ LongBowString *messageString = longBowString_CreateFormat("failed to induce an expected %s event.",
+ longBowEventType_GetName(expectedEvent));
+
+ LongBowLocation *location = longBowTestCase_CreateLocation(testCase);
+ LongBowEvent *event = longBowEvent_Create(expectedEvent, location, "", longBowString_ToString(messageString), NULL);
+
+ longBowReportRuntime_Event(event);
+ longBowEvent_Destroy(&event);
+ longBowString_Destroy(&messageString);
+
+ result = LONGBOW_STATUS_FAILED;
+ } else {
+ result = longBowEventType_GetStatus(actualEvent);
+ }
+
+ return result;
+}
+
+/*
+ * Invoke the test case function and see if it succeeds.
+ *
+ * The technique here is to assume the test case will succeed,
+ * setup a longjmp back to this function
+ * and then setup signal handling and invoke the test case.
+ * This essentially wraps the test function an catches and handles the abort()
+ * (SIGABRT) that results from the LongBow assertion or trap.
+ *
+ * If the test case simply returns (ie. the longjmp was never executed),
+ * then it was successful.
+ * Otherwise, the longjmp contains a code indicating the status captured by
+ * the signal handler that was invoked when the test code executed the abort() function.
+ * Extract relevant information from the current runtime context
+ * (which is always present whether in a unit test case or not)
+ *
+ * Note that it's actually not necessary for the test code to execute an abort(),
+ * it could invoke the longjmp() directly.
+ * Something that might be advantagous in the future.
+ */
+static LongBowStatus
+_longBowTestCase_Execute(LongBowTestCase *testCase)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ if (longBowConfig_IsTrace(longBowTestCase_GetConfiguration(testCase))) {
+ longBowReportTesting_Trace(" %s/%s/%s",
+ longBowTestRunner_GetName(longBowTestFixture_GetRunner(longBowTestCase_GetFixture(testCase))),
+ longBowTestFixture_GetName(longBowTestCase_GetFixture(testCase)),
+ longBowTestCase_GetName(testCase));
+ }
+
+ int receivedSignal = setjmp(longBowTestCaseAbort);
+ if (receivedSignal == 0) {
+ _longBowTestCase_TestInitSignals();
+
+ errno = 0;
+
+ LongBowClipBoard *testClipBoard = longBowTestFixture_GetClipBoard(longBowTestCase_GetFixture(testCase));
+
+ (testCase->testCase)(longBowTestFixture_GetRunner(longBowTestCase_GetFixture(testCase)),
+ longBowTestCase_GetFixture(testCase),
+ testCase,
+ testClipBoard,
+ longBowTestCaseAbort);
+ } else {
+ // We get here as the result of an extraordinary abort from the testCase invoked just above.
+ // Sort out the meaning of the received signal here.
+ //
+ // If an SIGABRT is received, we expect that the Global Runtime contains a valid LongBowEventType.
+ // If not, then an old-timey <assert.h> assert() was used and the programmer should be warned,
+ // or the system under test actually uses SIGABRT and the programmer is warned that this
+ // incompatible with LongBow.
+
+ LongBowEventType *event = NULL;
+ if (receivedSignal == SIGABRT) {
+ if (longBowRuntime_GetActualEventType(longBowRuntime_GetCurrentRuntime()) == NULL) {
+ char *testCaseString = longBowTestCase_ToString(testCase);
+ longBowReportRuntime_Warning("Warning: %s commingling LongBow with assert(3) or with SIGABRT will not work.\n", testCaseString);
+ free(testCaseString);
+ }
+
+ event = longBowRuntime_GetActualEventType(longBowRuntime_GetCurrentRuntime());
+ } else if (receivedSignal == SIGTERM) {
+ char *testCaseString = longBowTestCase_ToString(testCase);
+ longBowReportRuntime_Warning("\nWarning: %s premature termination.\n", testCaseString);
+ free(testCaseString);
+ event = longBowEventType_GetEventTypeForSignal(receivedSignal);
+ } else if (receivedSignal == SIGINT) {
+ char *testCaseString = longBowTestCase_ToString(testCase);
+ longBowReportRuntime_Warning("\nWarning: %s interrupted.\n", testCaseString);
+ free(testCaseString);
+ event = longBowEventType_GetEventTypeForSignal(receivedSignal);
+ } else {
+ event = longBowEventType_GetEventTypeForSignal(receivedSignal);
+ }
+
+ longBowRuntimeResult_SetEvent(longBowTestCase_GetActualResult(testCase), event);
+ }
+
+ result = _longBowTestCase_ExpectedVsActualEvent(testCase);
+
+ if (result == LONGBOW_STATUS_SUCCEEDED) {
+ if (longBowTestCase_GetEventEvaluationCount(testCase) == 0) {
+ result = LongBowStatus_IMPOTENT;
+ }
+ } else if (longBowStatus_IsFailed(result)) {
+ ;
+ }
+
+ memset(&longBowTestCaseAbort, 0, sizeof(longBowTestCaseAbort));
+
+ _longBowTestCase_TestFiniSignals();
+
+ return result;
+}
+
+static LongBowStatus
+_longBowTestCase_ExecuteOnce(LongBowTestCase *testCase)
+{
+ LongBowStatus result = LONGBOW_STATUS_FAILED;
+
+ LongBowTestFixture *fixture = longBowTestCase_GetFixture(testCase);
+
+ LongBowStatus setupStatus = longBowTestFixture_Setup(fixture, testCase);
+
+ if (longBowStatus_IsSuccessful(setupStatus) == true) {
+ LongBowStatus testCaseStatus = _longBowTestCase_Execute(testCase);
+
+ LongBowStatus tearDownStatus = longBowTestFixture_TearDown(fixture, testCase);
+
+ // Ensure that things only go from "bad" to "worse." If a test case is indicating a failure
+ // and yet the tear-down is also indicating something NOT successful (like a warning), don't
+ // demote the status from LONGBOW_STATUS_FAILED to LONGBOW_STATUS_TEARDOWN_WARNING.
+ // This is messy. Perhaps a better approach would be to structure status as an ordered arrangement of status.
+
+ result = testCaseStatus;
+
+ if (testCaseStatus == LONGBOW_STATUS_SUCCEEDED) {
+ if (tearDownStatus != LONGBOW_STATUS_SUCCEEDED) {
+ result = tearDownStatus;
+ }
+ }
+ }
+
+ return result;
+}
+
+static LongBowStatus
+_longBowTestCase_Iterate(LongBowTestCase *testCase)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ LongBowConfig *config = longBowTestCase_GetConfiguration(testCase);
+
+ uint32_t iterations = longBowConfig_GetUint32(config, 1, "%s/iterations", longBowTestCase_GetFullName(testCase));
+
+ for (uint32_t i = 0; i < iterations && longBowStatus_IsSuccessful(result); i++) {
+ LongBowRuntime *previousRuntime = longBowRuntime_SetCurrentRuntime(testCase->runtime);
+ result = _longBowTestCase_ExecuteOnce(testCase);
+ longBowRuntime_SetCurrentRuntime(previousRuntime);
+ }
+
+ return result;
+}
+
+/*
+ * Run a LongBowTestCase in a forked process.
+ *
+ * @param testCase The LongBowTestCase to run.
+ * @return 0
+ */
+static int
+_longBowTestCase_RunForked(LongBowTestCase *testCase)
+{
+ struct timeval startTime;
+ gettimeofday(&startTime, NULL);
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ exit(_longBowTestCase_Iterate(testCase));
+ } else {
+ // Rummage around in various things to obtain the post-mortem
+ // results of the test that was run in a separate process.
+ int waitStatus;
+ struct rusage rusage;
+#ifndef __ANDROID__
+ wait3(&waitStatus, 0, &rusage);
+#else
+ wait4(-1, &waitStatus, 0, &rusage);
+#endif
+ struct timeval endTime;
+ gettimeofday(&endTime, NULL);
+
+ struct timeval elapsedTime;
+ timersub(&endTime, &startTime, &elapsedTime);
+
+ longBowRuntimeResult_SetElapsedTime(longBowTestCase_GetActualResult(testCase), &elapsedTime);
+ longBowRuntimeResult_SetRUsage(longBowTestCase_GetActualResult(testCase), &rusage);
+ longBowRuntimeResult_SetStatus(longBowTestCase_GetActualResult(testCase), _longBowTestCase_ParseWaitStatus(waitStatus));
+ }
+ return 0;
+}
+
+/*
+ * Run a LongBowTestCase in this address space (ie. not a forked process).
+ *
+ * @param testCase The LongBowTestCase to run.
+ * @return 0
+ */
+static int
+_longBowTestCase_RunNonForked(LongBowTestCase *testCase)
+{
+ struct timeval startTime;
+ gettimeofday(&startTime, NULL);
+
+ LongBowStatus status = _longBowTestCase_Iterate(testCase);
+
+ struct timeval endTime;
+ gettimeofday(&endTime, NULL);
+
+ struct timeval elapsedTime;
+ timersub(&endTime, &startTime, &elapsedTime);
+
+ longBowRuntimeResult_SetElapsedTime(longBowTestCase_GetActualResult(testCase), &elapsedTime);
+ longBowRuntimeResult_SetStatus(longBowTestCase_GetActualResult(testCase), status);
+
+ return 0;
+}
+
+LongBowStatus
+longBowTestCase_GetExpectedStatus(const LongBowTestCase *testCase)
+{
+ return longBowRuntimeResult_GetStatus(longBowTestCase_GetExpectedResult(testCase));
+}
+
+LongBowTestCase *
+longBowTestCase_Run(const char *testCaseName,
+ const LongBowTestFixture *fixture,
+ LongBowTestCaseFunction *testCase,
+ const LongBowTestCaseMetaData *testCaseMetaData)
+{
+ LongBowTestCase *result = longBowTestCase_Create(testCaseName, fixture, testCase, testCaseMetaData);
+
+ if (result != NULL) {
+ if (longBowConfig_IsRunForked(longBowTestRunner_GetConfiguration(longBowTestFixture_GetRunner(fixture)))) {
+ _longBowTestCase_RunForked(result);
+ } else {
+ _longBowTestCase_RunNonForked(result);
+ }
+
+ longBowTestFixture_AddTestCase(fixture, result);
+ longBowReportTesting_DisplayTestCaseResult(result);
+ }
+ return result;
+}
+
+LongBowStatus
+longBowTestCase_GetStatus(const LongBowTestCase *testCase)
+{
+ return longBowRuntimeResult_GetStatus(longBowTestCase_GetActualResult(testCase));
+}
+
+static LongBowClipBoard *
+_longBowTestCase_GetClipBoard(const LongBowTestCase *testCase)
+{
+ return longBowTestFixture_GetClipBoard(testCase->fixture);
+}
+
+void *
+longBowTestCase_SetClipBoardData(const LongBowTestCase *testCase, void *data)
+{
+ return longBowClipBoard_Set(_longBowTestCase_GetClipBoard(testCase), "testCase", data);
+}
+
+void *
+longBowTestCase_GetClipBoardData(const LongBowTestCase *testCase)
+{
+ return longBowClipBoard_Get(_longBowTestCase_GetClipBoard(testCase), "testCase");
+}
+
+void *
+longBowTestCase_Set(const LongBowTestCase *testCase, const char *name, void *value)
+{
+ return longBowClipBoard_Set(_longBowTestCase_GetClipBoard(testCase), name, value);
+}
+
+void *
+longBowTestCase_Get(const LongBowTestCase *testCase, const char *name)
+{
+ return longBowClipBoard_Get(_longBowTestCase_GetClipBoard(testCase), name);
+}
+
+char *
+longBowClipBoard_GetCString(const LongBowTestCase *testCase, const char *name)
+{
+ return longBowClipBoard_GetAsCString(_longBowTestCase_GetClipBoard(testCase), name);
+}
+
+void *
+longBowTestCase_SetInt(const LongBowTestCase *testCase, const char *name, int value)
+{
+ return longBowClipBoard_SetInt(_longBowTestCase_GetClipBoard(testCase), name, (uint64_t) value);
+}
+
+void *
+longBowTestCase_SetCString(const LongBowTestCase *testCase, const char *name, char *value)
+{
+ return longBowClipBoard_SetCString(_longBowTestCase_GetClipBoard(testCase), name, value);
+}
+
+int
+longBowTestCase_GetInt(const LongBowTestCase *testCase, const char *name)
+{
+ return (intptr_t) longBowTestCase_Get(testCase, name);
+}
+
+LongBowConfig *
+longBowTestCase_GetConfiguration(const LongBowTestCase *testCase)
+{
+ return longBowTestRunner_GetConfiguration(longBowTestFixture_GetRunner(longBowTestCase_GetFixture(testCase)));
+}
+
+char *
+longBowTestCase_ToString(const LongBowTestCase *testCase)
+{
+ return strdup(longBowTestCase_GetFullName(testCase));
+}
+
+bool
+longBowTestCase_IsSuccessful(const LongBowTestCase *testCase)
+{
+ return longBowStatus_IsSuccessful(longBowTestCase_GetStatus(testCase));
+}
+
+bool
+longBowTestCase_IsFailed(const LongBowTestCase *testCase)
+{
+ return longBowStatus_IsFailed(longBowTestCase_GetStatus(testCase));
+}
+
+bool
+longBowTestCase_IsWarning(const LongBowTestCase *testCase)
+{
+ return longBowStatus_IsWarning(longBowTestCase_GetStatus(testCase));
+}
+
+bool
+longBowTestCase_IsIncomplete(const LongBowTestCase *testCase)
+{
+ return longBowStatus_IsIncomplete(longBowTestCase_GetStatus(testCase));
+}
diff --git a/longbow/src/LongBow/longBow_TestCase.h b/longbow/src/LongBow/longBow_TestCase.h
new file mode 100755
index 00000000..670adc84
--- /dev/null
+++ b/longbow/src/LongBow/longBow_TestCase.h
@@ -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.
+ */
+
+/**
+ * @file longBow_TestCase.h
+ * @ingroup internals
+ * @brief The interface and supporting functionality of a LongBow Test Case.
+ *
+ */
+#ifndef LONGBOWTESTCASE_H_
+#define LONGBOWTESTCASE_H_
+
+#include <setjmp.h>
+
+struct longbow_testcase;
+typedef struct longbow_testcase LongBowTestCase;
+
+#include <LongBow/longBow_TestCaseClipBoard.h>
+#include <LongBow/longBow_ClipBoard.h>
+
+#include <LongBow/longBow_TestRunner.h>
+#include <LongBow/longBow_TestFixture.h>
+#include <LongBow/longBow_RuntimeResult.h>
+#include <LongBow/longBow_TestCaseMetaData.h>
+
+typedef void (LongBowTestCaseFunction)(const LongBowTestRunner *, const LongBowTestFixture *, const LongBowTestCase *, const LongBowClipBoard *c, jmp_buf);
+
+/**
+ * Get the name of the given LongBowTestCase.
+ *
+ * @param [in] testCase A pointer to a `LongBowTestCase` instance.
+ *
+ * @return A pointer to an immutable C string.
+ *
+ * Example:
+ * @code
+ * const char *name = longBowTestCase_GetName(testCase);
+ * @endcode
+ */
+const char *longBowTestCase_GetName(const LongBowTestCase *testCase);
+
+/**
+ * Get the corresponding LongBowTestFixture for the given LongBowTestCase.
+ *
+ * @param [in] testCase A pointer to a LongBowTestCase instance.
+ *
+ * @return A pointer to the corresponding LongBowTestFixture.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+LongBowTestFixture *longBowTestCase_GetFixture(const LongBowTestCase *testCase);
+
+/**
+ * Create a LongBowTestCase instance.
+ *
+ * @param [in] testCaseName A nul-terminated C string of the test case name.
+ * @param [in] fixture A pointer to a valid LongBowTestFixture instance.
+ * @param [in] testCase A pointer to a test case function.
+ * @param [in] metaData A pointer to a LongBowTestCaseMetaData instance.
+ * @return A pointer to an allocated LongBowTestCase instance, that must be destroyed via longBowTestCase_Destroy().
+ */
+LongBowTestCase *longBowTestCase_Create(const char *testCaseName,
+ const LongBowTestFixture *fixture,
+ LongBowTestCaseFunction *testCase,
+ const LongBowTestCaseMetaData *metaData);
+
+/**
+ * Print command line and configuration help applicable to a Long Bow Test Case.
+ *
+ */
+void longBowTestCase_ConfigHelp(void);
+
+/**
+ * @param [in,out] testCasePtr A pointer to a pointer to a LongBowTestCase instance.
+ */
+void longBowTestCase_Destroy(LongBowTestCase **testCasePtr);
+
+/**
+ * Get the fully qualified name of the given `LongBowTestCase`.
+ *
+ * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+ *
+ * @return A constant nul-terminated, C string.
+ */
+const char *longBowTestCase_GetFullName(const LongBowTestCase *testCase);
+
+/**
+ *
+ * @param [in] testCaseName A nul-terminated C string of the test case name.
+ * @param [in] fixture A pointer to a valid LongBowTestFixture instance.
+ * @param [in] testCase A pointer to a test case function.
+ * @param [in] testCaseMetaData A pointer to a LongBowTestCaseMetaData instance.
+ * @return return
+ */
+LongBowTestCase *longBowTestCase_Run(const char *testCaseName,
+ const LongBowTestFixture *fixture,
+ LongBowTestCaseFunction *testCase,
+ const LongBowTestCaseMetaData *testCaseMetaData);
+
+/**
+ * Get the string representation of the given LongBowTestCase.
+ *
+ * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+ * @return An allocated, nul-terminated C string that must be deallocated via free(3)
+ */
+char *longBowTestCase_ToString(const LongBowTestCase *testCase);
+
+/**
+ * Return the LongBowStatus of the given test case.
+ *
+ * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+ * @return The LongBowStatus of the given test case.
+ */
+LongBowStatus longBowTestCase_GetStatus(const LongBowTestCase *testCase);
+
+/**
+ * Get the LongBowStatus value for the expected status of the given LongBowTestCase.
+ *
+ * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+ * @return A LongBowStatus value for the expected status of the given LongBowTestCase.
+ */
+LongBowStatus longBowTestCase_GetExpectedStatus(const LongBowTestCase *testCase);
+
+/**
+ * Get a pointer to the expected LongBowRuntimeResult value for the given LongBowTestCase.
+ *
+ * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+ * @return A LongBowStatus value for the expected status of the given LongBowTestCase.
+ */
+LongBowRuntimeResult *longBowTestCase_GetExpectedResult(const LongBowTestCase *testCase);
+
+/**
+ * Get the count of event evaluations performed during the execution of a LongBow Test Case.
+ *
+ * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+ *
+ * @return The count of event evaluations performed during the execution of a LongBow Test Case.
+ */
+size_t longBowTestCase_GetEventEvaluationCount(const LongBowTestCase *testCase);
+
+/**
+ *
+ * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+ * @return A LongBowRuntimeResult pointer.
+ */
+LongBowRuntimeResult *longBowTestCase_GetActualResult(const LongBowTestCase *testCase);
+
+/**
+ * Return <code>true</code> if the given test case was successful.
+ *
+ * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+ * @return <code>true</code> if the given test case succeeded.
+ */
+bool longBowTestCase_IsSuccessful(const LongBowTestCase *testCase);
+
+/**
+ * Return <code>true</code> if the given test case issued a warning.
+ *
+ * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+ * @return <code>true</code> if the given test case issued a warning.
+ */
+bool longBowTestCase_IsWarning(const LongBowTestCase *testCase);
+
+/**
+ * Return <code>true</code> if the given test case was incomplete.
+ *
+ * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+ * @return <code>true</code> if the given test case was incomplete.
+ */
+bool longBowTestCase_IsIncomplete(const LongBowTestCase *testCase);
+
+/**
+ * Return <code>true</code> if the given test case failed.
+ *
+ * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+ * @return <code>true</code> if the given test case failed.
+ */
+bool longBowTestCase_IsFailed(const LongBowTestCase *testCase);
+
+///**
+// * Place a value on the Test Case "clipboard"
+// *
+// * Every Test Case has an associated "clipboard" which is shared between the Test Fixture Setup,
+// * Test Case, and Test Fixture Tear Down.
+// *
+// * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+// * @param [in] data The value to share on the clipboard.
+// * @return The previous value on the "clipboard", or NULL if no previous value was set.
+// */
+//void *longBowTestCase_SetClipBoard(const LongBowTestCase *testCase, const char *name, void *data);
+
+///**
+// * Get the named clipboard data from the given `LongBowTestCase`.
+// *
+// * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+// * @param [in] name A nul-terminate, C string of the name of the clipboard entry.
+// */
+//void *longBowTestCase_GetClipBoard(const LongBowTestCase *testCase, const char *name);
+
+/**
+ * Get the LongBowConfig instance for the given LongBowTestCase instance.
+ *
+ * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+ *
+ * @return non-NULL The LongBowConfig instance for the given LongBowTestCase instance.
+ * @return NULL No LongBowConfig instance for the given LongBowTestCase.
+ */
+LongBowConfig *longBowTestCase_GetConfiguration(const LongBowTestCase *testCase);
+
+/**
+ * Get the clipboard data from the given `LongBowTestCase`.
+ *
+ * NOTE: Use `longBowTestCase_GetClipBoard`.
+ *
+ * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+ */
+void *longBowTestCase_GetClipBoardData(const LongBowTestCase *testCase);
+
+void *longBowTestCase_SetClipBoardData(const LongBowTestCase *testCase, void *data);
+
+void *longBowTestCase_Set(const LongBowTestCase *testCase, const char *name, void *value);
+
+void *longBowTestCase_Get(const LongBowTestCase *testCase, const char *name);
+
+char *longBowClipBoard_GetCString(const LongBowTestCase *testCase, const char *name);
+
+void *longBowTestCase_SetInt(const LongBowTestCase *testCase, const char *name, int value);
+
+void *longBowTestCase_SetCString(const LongBowTestCase *testCase, const char *name, char *value);
+
+int longBowTestCase_GetInt(const LongBowTestCase *testCase, const char *name);
+#endif // LONGBOWTESTCASE_H_
diff --git a/longbow/src/LongBow/longBow_TestCaseClipBoard.c b/longbow/src/LongBow/longBow_TestCaseClipBoard.c
new file mode 100755
index 00000000..acdf4c3d
--- /dev/null
+++ b/longbow/src/LongBow/longBow_TestCaseClipBoard.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/longBow_TestCaseClipBoard.h>
+#include <LongBow/private/longBow_Memory.h>
+
+struct longbow_testcase_clipboard {
+ /**
+ * A pointer to arbitrary data shared between the setup, test case, and teardown.
+ */
+ void *shared;
+};
+
+LongBowTestCaseClipBoard *
+longBowTestCaseClipBoard_Create(void *shared)
+{
+ LongBowTestCaseClipBoard *result = longBowMemory_Allocate(sizeof(LongBowTestCaseClipBoard));
+ longBowTestCaseClipBoard_Set(result, shared);
+ return result;
+}
+
+void
+longBowTestCaseClipBoard_Destroy(LongBowTestCaseClipBoard **clipBoardPtr)
+{
+ longBowMemory_Deallocate((void **) clipBoardPtr);
+}
+
+void *
+longBowTestCaseClipBoard_Get(const LongBowTestCaseClipBoard *clipBoard)
+{
+ return clipBoard->shared;
+}
+
+LongBowTestCaseClipBoard *
+longBowTestCaseClipBoard_Set(LongBowTestCaseClipBoard *clipBoard, void *shared)
+{
+ void *previousValue = clipBoard->shared;
+ clipBoard->shared = shared;
+ return previousValue;
+}
diff --git a/longbow/src/LongBow/longBow_TestCaseClipBoard.h b/longbow/src/LongBow/longBow_TestCaseClipBoard.h
new file mode 100755
index 00000000..4b8da1aa
--- /dev/null
+++ b/longbow/src/LongBow/longBow_TestCaseClipBoard.h
@@ -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.
+ */
+
+/**
+ * @file longBow_TestCaseClipboard.h
+ * @ingroup testing
+ * @brief LongBow Clipboard shared between the setup, test case, and teardown.
+ *
+ */
+#ifndef LongBow_longBowTestCaseClipBoard_h
+#define LongBow_longBowTestCaseClipBoard_h
+
+struct longbow_testcase_clipboard;
+
+/**
+ * @typedef LongBowTestCaseClipBoard
+ */
+typedef struct longbow_testcase_clipboard LongBowTestCaseClipBoard;
+
+/**
+ * Create a `LongBowTestCaseClipBoard` containing the shared data pointer.
+ *
+ * @param [in] shared A pointer to a value that is shared between the setup, test-case, and tear-down functions.
+ * @return A pointer to a valid LongBowTestCaseClipBoard instance.
+ *
+ * @see longBowTestCaseClipBoard_Destroy
+ */
+LongBowTestCaseClipBoard *longBowTestCaseClipBoard_Create(void *shared);
+
+/**
+ *
+ * @param [in,out] clipBoardPtr A pointer to a pointer to a LongBowTestCaseClipBoard instance.
+ */
+void longBowTestCaseClipBoard_Destroy(LongBowTestCaseClipBoard **clipBoardPtr);
+
+/**
+ *
+ * @param [in] clipBoard A pointer to a valid LongBowTestCaseClipBoard instance.
+ * @param [in] shared A pointer to a value that is shared between the setup, test-case, and tear-down functions.
+ * @return The previous value of the "clipboard", or NULL if there was no previous value.
+ */
+LongBowTestCaseClipBoard *longBowTestCaseClipBoard_Set(LongBowTestCaseClipBoard *clipBoard, void *shared);
+
+/**
+ *
+ * @param [in] clipBoard A pointer to a valid LongBowTestCaseClipBoard instance.
+ * @return The value currently stored on the clipboard.
+ */
+void *longBowTestCaseClipBoard_Get(const LongBowTestCaseClipBoard *clipBoard);
+#endif
diff --git a/longbow/src/LongBow/longBow_TestCaseMetaData.c b/longbow/src/LongBow/longBow_TestCaseMetaData.c
new file mode 100755
index 00000000..1596d60c
--- /dev/null
+++ b/longbow/src/LongBow/longBow_TestCaseMetaData.c
@@ -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.
+ */
+
+/**
+ */
+#include <LongBow/longBow_TestCaseMetaData.h>
diff --git a/longbow/src/LongBow/longBow_TestCaseMetaData.h b/longbow/src/LongBow/longBow_TestCaseMetaData.h
new file mode 100755
index 00000000..589b90ec
--- /dev/null
+++ b/longbow/src/LongBow/longBow_TestCaseMetaData.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.
+ */
+
+/**
+ */
+#ifndef longBow_TestCaseMetaData_h
+#define longBow_TestCaseMetaData_h
+
+#include <stdint.h>
+
+#include <LongBow/longBow_RuntimeResult.h>
+
+struct LongBowTestCaseMetaData {
+ const char *fileName;
+ const char *functionName;
+ uint32_t lineNumber;
+ LongBowRuntimeResult expectedResult;
+};
+
+typedef struct LongBowTestCaseMetaData LongBowTestCaseMetaData;
+
+#endif /* longBow_TestCaseMetaData_h */
diff --git a/longbow/src/LongBow/longBow_TestFixture.c b/longbow/src/LongBow/longBow_TestFixture.c
new file mode 100644
index 00000000..d4efc86f
--- /dev/null
+++ b/longbow/src/LongBow/longBow_TestFixture.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.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdio.h>
+
+#include <LongBow/private/longBow_ArrayList.h>
+#include <LongBow/private/longBow_Memory.h>
+#include <LongBow/private/longBow_String.h>
+
+#include <LongBow/longBow_TestFixture.h>
+#include <LongBow/longBow_TestFixtureConfig.h>
+#include <LongBow/longBow_TestCase.h>
+#include <LongBow/longBow_RuntimeResult.h>
+
+#include <LongBow/unit-test.h>
+
+/**
+ * @struct longbow_fixture
+ * @brief The LongBow Test Fixture.
+ *
+ * This structure is created and initialized by the LongBow Test Runner.
+ * When the Test Fixture represented by this structure is executed,
+ * this structure is updated with the results of each LongBow Test Case that belongs to this Fixture.
+ */
+struct longbow_fixture {
+ /**
+ * The name of this test fixture.
+ */
+ const char *name;
+
+ /**
+ * The fully qualified name of this test fixture.
+ */
+ char *fullName;
+
+ /**
+ *
+ */
+ LongBowTestFixtureConfig *config;
+
+ /**
+ * The Test Runner of this test fixture.
+ */
+ LongBowTestRunner *runner;
+
+ /**
+ * The `LongBowTestFixtureSummary` of this test fixture.
+ */
+ LongBowTestFixtureSummary summary;
+
+ /**
+ * A list of `LongBowTestCase` structures, one for each executed test case.
+ */
+ LongBowArrayList *testCases;
+
+ /**
+ * The function to call to setup the Test Fixture.
+ *
+ * This function is called before each Test Case is run.
+ * @param testCase The LongBow Test Case that is being set-up.
+ */
+ LongBowTestFixtureSetupFunction *setUp;
+
+ /**
+ * The function to call to execute the Test Fixture.
+ *
+ * @param testFixture A pointer to this `struct longbow_fixture` structure.
+ */
+ LongBowTestFixtureFunction *fixture;
+
+ /**
+ * The function to call to tear-down the Test Fixture.
+ *
+ * This function is called after each Test Case is run.
+ * @param testCase The LongBow Test Case that is being torn-down.
+ */
+ LongBowTestFixtureTearDownFunction *tearDown;
+};
+
+static void
+_longBowTestFixture_TestSucceeded(LongBowTestFixtureSummary *summary)
+{
+ summary->totalTested++;
+ summary->totalSucceeded++;
+}
+
+static void
+_longBowTestFixture_TestFailed(LongBowTestFixtureSummary *summary)
+{
+ summary->totalTested++;
+ summary->totalFailed++;
+}
+
+static void
+_longBowTestFixture_TestLeakedResources(LongBowTestFixtureSummary *summary)
+{
+ summary->totalTested++;
+ summary->totalFailed++;
+}
+
+static void
+_longBowTestFixture_TestSkipped(LongBowTestFixtureSummary *summary)
+{
+ summary->totalTested++;
+ summary->totalSkipped++;
+}
+
+static void
+_longBowTestFixture_TestSkipTests(LongBowTestFixtureSummary *summary)
+{
+ summary->totalTested++;
+ summary->totalSkipped++;
+}
+
+static void
+_longBowTestFixture_TestWarned(LongBowTestFixtureSummary *summary)
+{
+ summary->totalTested++;
+ summary->totalWarned++;
+}
+
+static void
+_longBowTestFixture_TestSetupFailed(LongBowTestFixtureSummary *summary)
+{
+ summary->totalTested++;
+ summary->totalSetupFailed++;
+}
+
+static void
+_longBowTestFixture_TestSignalled(LongBowTestFixtureSummary *summary)
+{
+ summary->totalTested++;
+ summary->totalSignalled++;
+}
+
+static void
+_longBowTestFixture_TestStopped(LongBowTestFixtureSummary *summary)
+{
+ summary->totalTested++;
+ summary->totalStopped++;
+}
+
+static void
+_longBowTestFixture_TestUnimplemented(LongBowTestFixtureSummary *summary)
+{
+ summary->totalTested++;
+ summary->totalUnimplemented++;
+}
+
+static void
+_longBowTestFixture_TestImpotent(LongBowTestFixtureSummary *summary)
+{
+ summary->totalTested++;
+ summary->totalUnimplemented++;
+}
+
+static void
+_longBowTestFixture_Untested(LongBowTestFixtureSummary *summary __attribute__((unused)))
+{
+}
+
+static void
+_longBowTestFixture_TearDownFailed(LongBowTestFixtureSummary *summary)
+{
+ summary->totalTested++;
+ summary->totalTearDownFailed++;
+}
+
+static void
+_longBowTestFixture_TearDownWarned(LongBowTestFixtureSummary *summary)
+{
+ summary->totalTested++;
+ summary->totalTearDownWarned++;
+}
+
+void
+longBowTestFixture_ConfigHelp(void)
+{
+ printf("Test Fixture options:\n");
+ printf(" --set <runnerName>/<fixtureName>/iterations=<integer> Run the named test fixture <integer> times.\n");
+ printf(" --set <runnerName>/<fixtureName>/enable=(true|false) Enable or disable execution of the named test fixture.\n");
+}
+
+bool
+longBowTestFixture_Config(LongBowConfig *config, const char *parameter)
+{
+ bool result = false;
+ return result;
+}
+
+LongBowTestFixture *
+longBowTestFixture_Create(const LongBowTestRunner *testRunner,
+ const char *fixtureName,
+ LongBowTestFixtureSetupFunction *setup,
+ LongBowTestFixtureFunction *fixtureFunction,
+ LongBowTestFixtureTearDownFunction *tearDown)
+{
+ LongBowTestFixture *fixture = longBowMemory_Allocate(sizeof(LongBowTestFixture));
+ if (fixture != NULL) {
+ fixture->runner = (LongBowTestRunner *) testRunner;
+ fixture->name = fixtureName;
+
+ int status = asprintf(&fixture->fullName, "%s/%s", longBowTestRunner_GetName(testRunner), fixtureName);
+ if (status == -1) {
+ return NULL;
+ }
+
+ fixture->testCases = longBowArrayList_Create((void (*)(void **))longBowTestCase_Destroy);
+ fixture->setUp = setup;
+ fixture->fixture = fixtureFunction;
+ fixture->tearDown = tearDown;
+ }
+
+ return fixture;
+}
+
+void
+longBowTestFixture_Destroy(LongBowTestFixture **fixturePtr)
+{
+ LongBowTestFixture *fixture = *fixturePtr;
+
+ free(fixture->fullName);
+
+ longBowArrayList_Destroy(&fixture->testCases);
+ longBowMemory_Deallocate((void **) fixturePtr);
+}
+
+const char *
+longBowTestFixture_GetFullName(const LongBowTestFixture *testFixture)
+{
+ return testFixture->fullName;
+}
+
+void
+longBowTestFixture_UpdateSummary(LongBowTestCase *longBowTestCase)
+{
+ switch (longBowRuntimeResult_GetStatus(longBowTestCase_GetActualResult(longBowTestCase))) {
+ case LONGBOW_STATUS_SUCCEEDED:
+ _longBowTestFixture_TestSucceeded(&longBowTestCase_GetFixture(longBowTestCase)->summary);
+ break;
+
+ case LONGBOW_STATUS_SKIPPED:
+ _longBowTestFixture_TestSkipped(&longBowTestCase_GetFixture(longBowTestCase)->summary);
+ break;
+
+ case LongBowStatus_WARNED:
+ _longBowTestFixture_TestWarned(&longBowTestCase_GetFixture(longBowTestCase)->summary);
+ break;
+
+ case LONGBOW_STATUS_SETUP_FAILED:
+ _longBowTestFixture_TestSetupFailed(&longBowTestCase_GetFixture(longBowTestCase)->summary);
+ break;
+
+ case LONGBOW_STATUS_SETUP_SKIPTESTS:
+ _longBowTestFixture_TestSkipTests(&longBowTestCase_GetFixture(longBowTestCase)->summary);
+ break;
+
+ case LONGBOW_STATUS_TEARDOWN_FAILED:
+ _longBowTestFixture_TearDownFailed(&longBowTestCase_GetFixture(longBowTestCase)->summary);
+ break;
+
+ case LongBowStatus_TEARDOWN_WARNED:
+ _longBowTestFixture_TearDownWarned(&longBowTestCase_GetFixture(longBowTestCase)->summary);
+ break;
+
+ case LONGBOW_STATUS_FAILED:
+ _longBowTestFixture_TestFailed(&longBowTestCase_GetFixture(longBowTestCase)->summary);
+ break;
+
+ case LongBowStatus_STOPPED:
+ _longBowTestFixture_TestStopped(&longBowTestCase_GetFixture(longBowTestCase)->summary);
+ break;
+
+ case LongBowStatus_UNIMPLEMENTED:
+ _longBowTestFixture_TestUnimplemented(&longBowTestCase_GetFixture(longBowTestCase)->summary);
+ break;
+
+ case LongBowStatus_IMPOTENT:
+ _longBowTestFixture_TestImpotent(&longBowTestCase_GetFixture(longBowTestCase)->summary);
+ break;
+
+ case LongBowStatus_UNTESTED:
+ _longBowTestFixture_Untested(&longBowTestCase_GetFixture(longBowTestCase)->summary);
+ break;
+
+ case LONGBOW_STATUS_MEMORYLEAK:
+ _longBowTestFixture_TestLeakedResources(&longBowTestCase_GetFixture(longBowTestCase)->summary);
+ break;
+
+ default:
+ if (longBowTestCase_GetActualResult(longBowTestCase)->status >= LongBowStatus_SIGNALLED) {
+ _longBowTestFixture_TestSignalled(&longBowTestCase_GetFixture(longBowTestCase)->summary);
+ } else {
+ printf("longBowTestFixture_UpdateSummary: unhandled status %d\n",
+ longBowTestCase_GetActualResult(longBowTestCase)->status);
+ }
+ }
+}
+
+void
+longBowTestFixture_AddTestCase(const LongBowTestFixture *fixture, LongBowTestCase *longBowTestCase)
+{
+ longBowTestFixture_UpdateSummary(longBowTestCase);
+
+ longBowArrayList_Add(fixture->testCases, longBowTestCase);
+}
+
+LongBowTestCase *
+longBowTestFixture_GetTestCase(const LongBowTestFixture *fixture, size_t index)
+{
+ LongBowTestCase *testCase = longBowArrayList_Get(fixture->testCases, index);
+
+ return testCase;
+}
+
+const char *
+longBowTestFixture_GetName(const LongBowTestFixture *fixture)
+{
+ return fixture->name;
+}
+
+const LongBowTestFixtureSummary *
+longBowTestFixture_GetSummary(const LongBowTestFixture *fixture)
+{
+ return &(fixture->summary);
+}
+
+size_t
+longBowTestFixture_GetTestCaseCount(const LongBowTestFixture *fixture)
+{
+ return longBowArrayList_Length(fixture->testCases);
+}
+
+LongBowStatus
+longBowTestFixture_Setup(LongBowTestFixture *fixture, LongBowTestCase *testCase)
+{
+ if (longBowConfig_IsTrace(longBowTestRunner_GetConfiguration(longBowTestFixture_GetRunner(fixture)))) {
+ longBowReportTesting_Trace(" %s/%s: setup",
+ longBowTestRunner_GetName(longBowTestFixture_GetRunner(fixture)),
+ longBowTestFixture_GetName(fixture));
+ }
+ LongBowClipBoard *testClipBoard = longBowTestFixture_GetClipBoard(fixture);
+ LongBowStatus result = (longBowTestCase_GetFixture(testCase)->setUp)(longBowTestFixture_GetRunner(fixture), fixture, testCase, testClipBoard);
+ return result;
+}
+
+LongBowStatus
+longBowTestFixture_TearDown(LongBowTestFixture *fixture, LongBowTestCase *testCase)
+{
+ if (longBowConfig_IsTrace(longBowTestRunner_GetConfiguration(longBowTestFixture_GetRunner(fixture)))) {
+ longBowReportTesting_Trace(" %s/%s: tearDown",
+ longBowTestRunner_GetName(longBowTestFixture_GetRunner(fixture)),
+ longBowTestFixture_GetName(fixture));
+ }
+ LongBowClipBoard *testClipBoard = longBowTestFixture_GetClipBoard(fixture);
+ LongBowStatus result = (longBowTestCase_GetFixture(testCase)->tearDown)(longBowTestFixture_GetRunner(fixture), fixture, testCase, testClipBoard);
+ return result;
+}
+
+LongBowStatus
+longBowTestFixture_GetStatus(const LongBowTestFixture *fixture)
+{
+ size_t nTestCases = longBowTestFixture_GetTestCaseCount(fixture);
+
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ // Just return the status of the first non-successful test case.
+ for (size_t i = 0; i < nTestCases; i++) {
+ LongBowTestCase *testCase = longBowTestFixture_GetTestCase(fixture, i);
+ if (!longBowTestCase_IsSuccessful(testCase)) {
+ result = longBowTestCase_GetStatus(testCase);
+ break;
+ }
+ }
+ return result;
+}
+
+bool
+longBowTestFixture_IsSuccessful(const LongBowTestFixture *testFixture)
+{
+ return longBowStatus_IsSuccessful(longBowTestFixture_GetStatus(testFixture));
+}
+
+char *
+longBowTestFixture_ToString(const LongBowTestFixture *fixture)
+{
+ char *runnerString = longBowTestRunner_ToString(longBowTestFixture_GetRunner(fixture));
+
+ char *string;
+ if (asprintf(&string, "%s/%s", runnerString, longBowTestFixture_GetName(fixture)) == -1) {
+ return NULL;
+ }
+
+ free(runnerString);
+
+ return string;
+}
+
+LongBowTestFixture *
+longBowTestFixture_Run(const LongBowTestRunner *testRunner,
+ const char *fixtureName,
+ const LongBowTestFixtureConfig *config,
+ LongBowTestFixtureSetupFunction *setup,
+ LongBowTestFixtureFunction *fixtureRun,
+ LongBowTestFixtureTearDownFunction *tearDown)
+{
+ LongBowTestFixture *testFixture = longBowTestFixture_Create(testRunner, fixtureName, setup, fixtureRun, tearDown);
+
+ LongBowConfig *configuration = longBowTestRunner_GetConfiguration(testRunner);
+
+ bool enabled = longBowConfig_GetBoolean(configuration, config->enabled, "%s/enabled", longBowTestFixture_GetFullName(testFixture));
+ unsigned long iterations = longBowConfig_GetUint32(configuration, 1, "%s/iterations", longBowTestFixture_GetFullName(testFixture));
+
+ if (enabled) {
+ for (unsigned long i = 0; i < iterations; i++) {
+ (*testFixture->fixture)(testRunner, testFixture);
+ }
+ longBowTestRunner_AddFixture(testFixture->runner, testFixture);
+ }
+
+ return testFixture;
+}
+
+LongBowTestRunner *
+longBowTestFixture_GetRunner(const LongBowTestFixture *fixture)
+{
+ return fixture->runner;
+}
+
+LongBowClipBoard *
+longBowTestFixture_GetClipBoard(const LongBowTestFixture *fixture)
+{
+ return longBowTestRunner_GetClipBoard(fixture->runner);
+}
diff --git a/longbow/src/LongBow/longBow_TestFixture.h b/longbow/src/LongBow/longBow_TestFixture.h
new file mode 100644
index 00000000..926f3e03
--- /dev/null
+++ b/longbow/src/LongBow/longBow_TestFixture.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 longBow_TestFixture.h
+ * @ingroup internals
+ * @brief Manage the execution of Test Cases.
+ *
+ * A Test Fixture manages the individual execution of Test Cases.
+ *
+ */
+#ifndef LongBowTestFixture_H_
+#define LongBowTestFixture_H_
+
+#include <string.h>
+
+struct longbow_fixture;
+
+/**
+ * @typedef LongBowTestFixture
+ * @brief The LongBow Test Fixture.
+ *
+ * This structure is created and initialized by the LongBow Test Runner.
+ * When the Test Fixture represented by this structure is executed,
+ * this structure is updated with the results of each LongBow Test Case that belongs to this Fixture.
+ */
+typedef struct longbow_fixture LongBowTestFixture;
+
+#include <LongBow/longBow_ClipBoard.h>
+#include <LongBow/longBow_TestRunner.h>
+#include <LongBow/longBow_TestCase.h>
+#include <LongBow/longBow_TestFixtureConfig.h>
+
+typedef void (LongBowTestFixtureFunction)(const LongBowTestRunner *testRunner, const LongBowTestFixture *testFixture);
+
+typedef int (LongBowTestFixtureSetupFunction)(const LongBowTestRunner *, const LongBowTestFixture *, const LongBowTestCase *, LongBowClipBoard *);
+
+typedef int (LongBowTestFixtureTearDownFunction)(const LongBowTestRunner *, const LongBowTestFixture *, const LongBowTestCase *, LongBowClipBoard *);
+
+/**
+ * @typedef LongBowTestFixtureSummary
+ * @brief The summary for a test fixture.
+ */
+typedef struct longbow_fixture_summary {
+ /**
+ * The total number of test cases executed.
+ */
+ unsigned int totalTested;
+ /**
+ * The number of test cases that succeeded.
+ */
+ unsigned int totalSucceeded;
+ /**
+ * The number of test cases that failed.
+ */
+ unsigned int totalFailed;
+ /**
+ * The number of test cases that were skipped.
+ */
+ unsigned int totalSkipped;
+ /**
+ * The number of test cases that issued a warning.
+ */
+ unsigned int totalWarned;
+ /**
+ * The number of test cases that setup failed.
+ */
+ unsigned int totalSetupFailed;
+ /**
+ * The number of test cases that failed due to an signal.
+ */
+ unsigned int totalSignalled;
+ /**
+ * The number of test cases that failed due to a stop signal.
+ */
+ unsigned int totalStopped;
+ /**
+ * The number of test cases in which the tear-down failed.
+ */
+ unsigned int totalTearDownFailed;
+ /**
+ * The number of test cases in which the tear-down issued a warning.
+ */
+ unsigned int totalTearDownWarned;
+ /**
+ * The number of test cases that existed but indicated they were unimplemented.
+ */
+ unsigned int totalUnimplemented;
+} LongBowTestFixtureSummary;
+
+/**
+ * Update the summary information from the given LongBowTestCase.
+ *
+ * @param testCase A pointer to a valid LongBowTestCase instance.
+ */
+void longBowTestFixture_UpdateSummary(LongBowTestCase *testCase);
+
+/**
+ *
+ * @param testFixture A pointer to a valid LongBowTestFixture instance.
+ * @param testCase A pointer to a valid LongBowTestCase instance.
+ */
+void longBowTestFixture_AddTestCase(const LongBowTestFixture *testFixture, LongBowTestCase *testCase);
+
+/**
+ *
+ * @param testFixture A pointer to a valid LongBowTestFixture instance.
+ * @param index The index of the instance to get.
+ * @return A pointer to the LongBowTestCase instance at the given index.
+ */
+LongBowTestCase *longBowTestFixture_GetTestCase(const LongBowTestFixture *testFixture, size_t index);
+
+/**
+ *
+ * @param testFixture A pointer to a valid LongBowTestFixture instance.
+ * @return A pointer ot the LongBowTestRunner instance of the given LongBowTestFixture.
+ */
+LongBowTestRunner *longBowTestFixture_GetRunner(const LongBowTestFixture *testFixture);
+
+/**
+ *
+ * @param testFixture A pointer to a valid LongBowTestFixture instance.
+ * @return A pointer to the C string of the name of the given LongBowTestFixture.
+ */
+const char *longBowTestFixture_GetName(const LongBowTestFixture *testFixture);
+
+/**
+ *
+ * @param testFixture A pointer to a valid LongBowTestFixture instance.
+ * @return The number of LongBow Test Cases in the given LongBowTestFixture.
+ */
+size_t longBowTestFixture_GetTestCaseCount(const LongBowTestFixture *testFixture);
+
+/**
+ * Initialise a {@link LongBowTestFixture} structure with the given parameters.
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ * @param [in] fixtureName The name of this Test Fixture.
+ * @param [in] setup A pointer to the function to call before invoking the first Test Case.
+ * @param [in] fixtureFunction A pointer to the function to call that will run each Test Case.
+ * @param [in] tearDown A pointer to the function to call after invoking the last Test Case.
+ * @return A pointer to an allocated LongBowTestFixture instance that must be deallocated via LongBowTestFixture_Destroy.
+ */
+LongBowTestFixture *longBowTestFixture_Create(const LongBowTestRunner *testRunner,
+ const char *fixtureName,
+ LongBowTestFixtureSetupFunction *setup,
+ LongBowTestFixtureFunction *fixtureFunction,
+
+ LongBowTestFixtureTearDownFunction *tearDown);
+
+/**
+ * Destroy a LongBowTestFixture structure.
+ *
+ * @param fixturePtr A pointer to a LongBowTestFixture structure pointer.
+ */
+void longBowTestFixture_Destroy(LongBowTestFixture **fixturePtr);
+
+/**
+ * Get the fully qualified name of the given `LongBowTestFixture`.
+ *
+ * @param [in] testFixture A pointer to a valid LongBowTestCase instance.
+ *
+ * @return A constant nul-terminated, C string.
+ */
+const char *longBowTestFixture_GetFullName(const LongBowTestFixture *testFixture);
+
+void longBowTestFixture_ConfigHelp(void);
+
+bool longBowTestFixture_Config(LongBowConfig *config, const char *parameter);
+
+/**
+ * Execute a LongBow Test Fixture.
+ *
+ * The Test Fixture will execute Test Cases in the order they appear in the Test Fixture function.
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ * @param [in] fixtureName The name of this Test Fixture.
+ * @param [in] config A pointer to a LongBowTestFixtureConfig to use when running the Test Fixture.
+ * @param [in] setup A pointer to the function to call before invoking the first Test Case.
+ * @param [in] fixtureRun A pointer to the function to call that will run each Test Case.
+ * @param [in] tearDown A pointer to the function to call after invoking the last Test Case.
+ * @return An allocated structure representing this Test Fixture.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see LONGBOW_TEST_FIXTURE
+ */
+LongBowTestFixture *longBowTestFixture_Run(const LongBowTestRunner *testRunner,
+ const char *fixtureName,
+ const LongBowTestFixtureConfig *config,
+ LongBowTestFixtureSetupFunction *setup,
+ LongBowTestFixtureFunction *fixtureRun,
+ LongBowTestFixtureTearDownFunction *tearDown);
+
+/**
+ * Get the status of the given LongBow Test Fixture.
+ *
+ * @param testFixture A pointer to a valid LongBowTestFixture instance.
+ * @return The `LongBowStatus` of the given Test Fixture.
+ */
+LongBowStatus longBowTestFixture_GetStatus(const LongBowTestFixture *testFixture);
+
+/**
+ * Return <code>true</code> if the given test case was successful.
+ *
+ * @param testFixture A pointer to a valid LongBowTestFixture instance.
+ * @return `true` if the given test case was successful.
+ */
+bool longBowTestFixture_IsSuccessful(const LongBowTestFixture *testFixture);
+
+/**
+ * Get a pointer to {@link LongBowTestFixtureSummary} for the given Test Fixture.
+ *
+ * @param testFixture A pointer to a valid LongBowTestFixture instance.
+ * @return A pointer to {@link LongBowTestFixtureSummary} for the given Test Fixture.
+ */
+const LongBowTestFixtureSummary *longBowTestFixture_GetSummary(const LongBowTestFixture *testFixture);
+
+/**
+ * Perform a test case setup.
+ *
+ * @param [in] testFixture A pointer to a valid LongBowTestFixture instance.
+ * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+ * @return The `LongBowStatus` returned from the setup function.
+ */
+LongBowStatus longBowTestFixture_Setup(LongBowTestFixture *testFixture, LongBowTestCase *testCase);
+
+/**
+ * Perform a test case teardown.
+ *
+ * @param testFixture A pointer to a valid LongBowTestFixture instance.
+ * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+ * @return The `LongBowStatus` returned from the teardown function.
+ */
+LongBowStatus longBowTestFixture_TearDown(LongBowTestFixture *testFixture, LongBowTestCase *testCase);
+
+/**
+ * Get the clipboard that belongs to the given Test Fixture.
+ *
+ * Every LongBow test fixure has an associated "clipboard" that is specific to that fixture and
+ * is shared between the test runner setup and tear down functions.
+ * Test Runner setup may store things on the test fixture's clipboard,
+ * the test fixture may access them and the tear down destroy them.
+ *
+ * @param [in] testFixture A pointer to a valid LongBowTestFixture instance.
+ * @return The `LongBowTestCaseClipBoard` for the given `LongBowTestFixture`.
+ *
+ * @see longBowTestCase_GetClipBoard
+ */
+LongBowClipBoard *longBowTestFixture_GetClipBoard(const LongBowTestFixture *testFixture);
+
+/**
+ * Compose a C string representing the current state of the given `LongBowTestFixture`.
+ *
+ * @param [in] testFixture A pointer to a valid LongBowTestFixture instance.
+ * @return An allocated, nul-terminated C string that must be deallocated via free(3)
+ */
+char *longBowTestFixture_ToString(const LongBowTestFixture *testFixture);
+#endif // LongBowTestFixture_H_
diff --git a/longbow/src/LongBow/longBow_TestFixtureConfig.c b/longbow/src/LongBow/longBow_TestFixtureConfig.c
new file mode 100755
index 00000000..756c908a
--- /dev/null
+++ b/longbow/src/LongBow/longBow_TestFixtureConfig.c
@@ -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.
+ */
+
+/**
+ */
+#include <stdio.h>
+
+#include <LongBow/longBow_TestFixtureConfig.h>
+#include <LongBow/private/longBow_Memory.h>
+
+LongBowTestFixtureConfig *
+longBowTestFixtureConfig_Create(const char *name, bool enabled)
+{
+ LongBowTestFixtureConfig *result = longBowMemory_Allocate(sizeof(LongBowTestFixtureConfig));
+
+ result->name = longBowMemory_StringCopy(name);
+ result->enabled = enabled;
+
+ return result;
+}
+
+void
+longBowTestFixtureConfig_Destroy(LongBowTestFixtureConfig **configPtr)
+{
+ LongBowTestFixtureConfig *config = *configPtr;
+
+ longBowMemory_Deallocate((void **) &config->name);
+ longBowMemory_Deallocate((void **) configPtr);
+}
diff --git a/longbow/src/LongBow/longBow_TestFixtureConfig.h b/longbow/src/LongBow/longBow_TestFixtureConfig.h
new file mode 100755
index 00000000..0ccaf538
--- /dev/null
+++ b/longbow/src/LongBow/longBow_TestFixtureConfig.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 longBow_TestFixtureConfig.h
+ * @ingroup testing
+ * @brief The Test Fixture configuration interface
+ *
+ */
+#ifndef LongBow_longBow_FixtureConfig_h
+#define LongBow_longBow_FixtureConfig_h
+#include <stdbool.h>
+
+struct longbow_fixture_config {
+ char *name;
+
+ bool enabled;
+};
+typedef struct longbow_fixture_config LongBowTestFixtureConfig;
+
+/**
+ * Create and initialise a LongBowTestFixtureConfig instance.
+ *
+ * @param [in] name The name of the Test Fixture
+ * @param [in] enabled True if the fixture is enabled, false otherwise.
+ *
+ * @return non-NULL A pointer to an allocated `LongBowTestFixtureConfig` isntance that must be destroyed via `longBowTestFixtureConfig_Destroy`.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ * @see longBowTestFixtureConfig_Destroy
+ */
+LongBowTestFixtureConfig *longBowTestFixtureConfig_Create(const char *name, bool enabled);
+
+/**
+ * Destroy a LongBowTestFixtureConfig intance.
+ *
+ * @param [in,out] configPtr A pointer to a pointer to a `LongBowTestFixtureConfig` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ *
+ * @see longBowTestFixtureConfig_Create
+ */
+void longBowTestFixtureConfig_Destroy(LongBowTestFixtureConfig **configPtr);
+#endif // LongBow_longBow_FixtureConfig_h
diff --git a/longbow/src/LongBow/longBow_TestRunner.c b/longbow/src/LongBow/longBow_TestRunner.c
new file mode 100644
index 00000000..730333f4
--- /dev/null
+++ b/longbow/src/LongBow/longBow_TestRunner.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <assert.h>
+#include <inttypes.h>
+
+#include <LongBow/unit-test.h>
+
+#include <LongBow/longBow_TestRunner.h>
+#include <LongBow/longBow_Properties.h>
+
+#include <LongBow/private/longBow_String.h>
+#include <LongBow/private/longBow_Memory.h>
+#include <LongBow/private/longBow_ArrayList.h>
+
+struct LongBowTestRunner {
+ const char *name; /**< The name of this LongBow test runner. */
+
+ LongBowStatus (*testRunnerSetup)(LongBowTestRunner *); /**< The Test Runner Setup function */
+
+ void (*testRunner)(LongBowTestRunner *); /**< The Test Case Runner function */
+
+ LongBowStatus (*testRunnerTearDown)(LongBowTestRunner *); /**< The Test Runner TearDown function */
+
+ LongBowArrayList *fixtures; /**< The LongBowTestFixtures of this Test Runner */
+
+ LongBowConfig *configuration; /**< The LongBowConfiguration for this Test Runner. */
+
+ /**
+ * The clipboard of information shared between the fixture setup,
+ * the test case, and the fixture tear-down.
+ */
+ LongBowClipBoard *clipBoard;
+};
+
+void
+longBowTestRunner_ConfigHelp(void)
+{
+ printf("Test Runner options:\n");
+ printf(" --set <testRunnerName>/iterations=<count> Run the named test runner <count> times\n");
+}
+
+bool
+longBowTestRunner_Config(LongBowConfig *config, const char *parameter)
+{
+ bool result = false;
+ LongBowArrayList *tokens = longBowString_Tokenise(parameter, "-=");
+ if (tokens != NULL) {
+ if (longBowArrayList_Length(tokens) == 2) {
+ result = longBowConfig_SetProperty(config, longBowArrayList_Get(tokens, 0), longBowArrayList_Get(tokens, 1));
+ }
+ longBowArrayList_Destroy(&tokens);
+ }
+ return result;
+}
+
+const char *
+longBowTestRunner_GetName(const LongBowTestRunner *testRunner)
+{
+ assert(testRunner != NULL);
+ return testRunner->name;
+}
+
+void
+longBowTestRunner_AddFixture(LongBowTestRunner *testRunner, LongBowTestFixture *testFixture)
+{
+ longBowArrayList_Add(testRunner->fixtures, testFixture);
+}
+
+LongBowTestRunner *
+longBowTestRunner_Create(const char *name,
+ LongBowTestRunnerSetUp *setup,
+ LongBowTestRunnerRun *runner,
+ LongBowTestRunnerTearDown *tearDown)
+{
+ LongBowTestRunner *testRunner = longBowMemory_Allocate(sizeof(LongBowTestRunner));
+
+ if (testRunner != NULL) {
+ testRunner->name = name;
+ testRunner->testRunnerSetup = setup;
+ testRunner->testRunner = runner;
+ testRunner->testRunnerTearDown = tearDown;
+ testRunner->fixtures = longBowArrayList_Create((void (*)(void **))longBowTestFixture_Destroy);
+ testRunner->clipBoard = longBowClipBoard_Create();
+ }
+ return testRunner;
+}
+
+void
+longBowTestRunner_Destroy(LongBowTestRunner **testRunnerPtr)
+{
+ if (testRunnerPtr != NULL) {
+ LongBowTestRunner *testRunner = *testRunnerPtr;
+
+ longBowArrayList_Destroy(&testRunner->fixtures);
+ if (testRunner->clipBoard) {
+ longBowClipBoard_Destroy(&testRunner->clipBoard);
+ }
+ if (testRunner != NULL) {
+ longBowMemory_Deallocate((void **) testRunnerPtr);
+ }
+ }
+}
+
+LongBowTestRunner *
+longBowTestRunner_Run(LongBowTestRunner *testRunner)
+{
+ LongBowConfig *configuration = longBowTestRunner_GetConfiguration(testRunner);
+ unsigned long iterations = longBowConfig_GetUint32(configuration, 1,
+ "%s/iterations", longBowTestRunner_GetName(testRunner));
+
+ if (longBowConfig_IsTrace(configuration)) {
+ longBowReportTesting_Trace("%s: setup", longBowTestRunner_GetName(testRunner));
+ }
+ LongBowStatus setupStatus = (*testRunner->testRunnerSetup)(testRunner);
+
+ if (setupStatus != LONGBOW_STATUS_SETUP_SKIPTESTS) {
+ if (!longBowStatus_IsSuccessful(setupStatus)) {
+ char *statusString = longBowStatus_ToString(setupStatus);
+ printf("Warning: %s setup returned: %s.\n", testRunner->name, statusString);
+ free(statusString);
+ return testRunner;
+ }
+
+ for (unsigned long i = 0; i < iterations; i++) {
+ if (longBowConfig_IsTrace(configuration)) {
+ longBowReportTesting_Trace("%s: run", longBowTestRunner_GetName(testRunner));
+ }
+ (*testRunner->testRunner)(testRunner);
+ }
+
+ if (longBowConfig_IsTrace(configuration)) {
+ longBowReportTesting_Trace("%s: tear-down", longBowTestRunner_GetName(testRunner));
+ }
+
+ LongBowStatus tearDownStatus = (*testRunner->testRunnerTearDown)(testRunner);
+ if (!longBowStatus_IsSuccessful(tearDownStatus)) {
+ char *statusString = longBowStatus_ToString(tearDownStatus);
+ printf("Warning: %s tear-down returned: %s.\n", testRunner->name, statusString);
+ free(statusString);
+ return testRunner;
+ }
+ }
+
+ return testRunner;
+}
+
+char *
+longBowTestRunner_ToString(const LongBowTestRunner *runner)
+{
+ LongBowString *string = longBowString_CreateFormat("%s", longBowTestRunner_GetName(runner));
+
+ char *cString = longBowString_ToString(string);
+ longBowString_Destroy(&string);
+ return cString;
+}
+
+LongBowTestFixture *
+longBowTestRunner_GetFixture(const LongBowTestRunner *testRunner, size_t index)
+{
+ return longBowArrayList_Get(testRunner->fixtures, index);
+}
+
+size_t
+longBowTestRunner_GetFixtureCount(const LongBowTestRunner *testRunner)
+{
+ return longBowArrayList_Length(testRunner->fixtures);
+}
+
+LongBowConfig *
+longBowTestRunner_GetConfiguration(const LongBowTestRunner *testRunner)
+{
+ return testRunner->configuration;
+}
+
+LongBowStatus
+longBowTestRunner_GetStatus(const LongBowTestRunner *testRunner)
+{
+ LongBowStatus result = LONGBOW_STATUS_SUCCEEDED;
+
+ // Just return the status of the first non-successful Test Fixture.
+ size_t nTestFixtures = longBowTestRunner_GetFixtureCount(testRunner);
+ for (size_t i = 0; i < nTestFixtures; i++) {
+ LongBowTestFixture *fixture = longBowTestRunner_GetFixture(testRunner, i);
+ if (!longBowTestFixture_IsSuccessful(fixture)) {
+ result = longBowTestFixture_GetStatus(fixture);
+ break;
+ }
+ }
+ return result;
+}
+
+bool
+longBowTestRunner_IsSuccessful(const LongBowTestRunner *testRunner)
+{
+ return longBowStatus_IsSuccessful(longBowTestRunner_GetStatus(testRunner));
+}
+
+bool
+longBowTestRunner_IsFailed(const LongBowTestCase *testCase)
+{
+ return longBowStatus_IsFailed(longBowTestCase_GetStatus(testCase));
+}
+
+bool
+longBowTestRunner_IsWarning(const LongBowTestRunner *testCase)
+{
+ return longBowStatus_IsWarning(longBowTestRunner_GetStatus(testCase));
+}
+
+bool
+longBowTestRunner_IsIncomplete(const LongBowTestCase *testCase)
+{
+ return longBowStatus_IsIncomplete(longBowTestCase_GetStatus(testCase));
+}
+
+void
+longBowTestRunner_SetConfiguration(LongBowTestRunner *testRunner, LongBowConfig *config)
+{
+ testRunner->configuration = config;
+}
+
+LongBowClipBoard *
+longBowTestRunner_GetClipBoard(const LongBowTestRunner *testRunner)
+{
+ return testRunner->clipBoard;
+}
+
+bool
+longBowTestRunner_SetClipBoardData(const LongBowTestRunner *testRunner, void *shared)
+{
+ return longBowClipBoard_Set(longBowTestRunner_GetClipBoard(testRunner), "testRunner", shared);
+}
+
+void *
+longBowTestRunner_GetClipBoardData(const LongBowTestRunner *testRunner)
+{
+ return longBowClipBoard_Get(longBowTestRunner_GetClipBoard(testRunner), "testRunner");
+}
diff --git a/longbow/src/LongBow/longBow_TestRunner.h b/longbow/src/LongBow/longBow_TestRunner.h
new file mode 100644
index 00000000..d787a17c
--- /dev/null
+++ b/longbow/src/LongBow/longBow_TestRunner.h
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 longBow_TestRunner.h
+ * @ingroup testing
+ * @brief LongBow Test Runner Support.
+ *
+ */
+#ifndef LONGBOWRUNNER_H_
+#define LONGBOWRUNNER_H_
+
+#include <stdbool.h>
+
+struct LongBowTestRunner;
+/**
+ * @typedef LongBowRunner
+ * @brief The LongBow Test Runner
+ */
+typedef struct LongBowTestRunner LongBowRunner;
+
+typedef struct LongBowTestRunner LongBowTestRunner;
+
+#include <LongBow/longBow_Config.h>
+#include <LongBow/longBow_Status.h>
+#include <LongBow/longBow_TestCase.h>
+#include <LongBow/longBow_TestFixture.h>
+
+/**
+ * The function prototype for a LongBow Test Runner set-up function.
+ *
+ * @param testRunner A pointer to the associated LongBowTestRunner.
+ * @return A LongBowStatus value indicating the result of the set-up.
+ */
+typedef LongBowStatus (LongBowTestRunnerSetUp)(LongBowTestRunner *testRunner);
+
+/**
+ * The function prototype for a LongBow Test Runner function.
+ *
+ * @param testRunner A pointer to the associated LongBowTestRunner.
+ */
+typedef void (LongBowTestRunnerRun)(LongBowTestRunner *testRunner);
+
+/**
+ * The function prototype for a LongBow Test Runner tear-down function.
+ *
+ * @param testRunner A pointer to the associated LongBowTestRunner.
+ * @return A LongBowStatus value indicating the result of the tear-down.
+ */
+typedef LongBowStatus (LongBowTestRunnerTearDown)(LongBowTestRunner *testRunner);
+
+/**
+ * Allocate and initialise a LongBowTestRunner structure with the given parameters.
+ *
+ * See <code>longBowTestRunner_Destroy</code> to destroy the result.
+ *
+ * The parameters may be static values (ie. not allocated) supplied by the caller
+ * and they are not subject to free in <code>longBowTestRunner_Destroy</code>.
+ *
+ * @param [in] name The name of the LongBow test runner as a null-terminated string.
+ * @param [in] setup The setup function for the Test Runner
+ * @param [in] testRunner The function to call to execute the Test Runner.
+ * @param [in] tearDown The function to call to tear-down the Test Runner.
+ * @return An allocated LongBowTestRunner structure representing a Test Runner.
+ */
+LongBowTestRunner *longBowTestRunner_Create(const char *name,
+ LongBowTestRunnerSetUp *setup,
+ LongBowTestRunnerRun *testRunner,
+ LongBowTestRunnerTearDown *tearDown);
+
+/**
+ * Destroy a previously allocated LongBowTestRunner structure.
+ *
+ * @param [in,out] testRunnerPtr A pointer to a previously allocated LongBowTestRunner structure.
+ */
+void longBowTestRunner_Destroy(LongBowTestRunner **testRunnerPtr);
+
+/**
+ * Get the name of the given LongBowTestRunner.
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ * @return The name of the Test Runner.
+ */
+const char *longBowTestRunner_GetName(const LongBowTestRunner *testRunner);
+
+/**
+ * Get the `LongBowClipBoard` for the given LongBowTestRunner.
+ *
+ * Every LongBow test case has an associated "clipboard" that is specific to a test case
+ * and is shared between the fixture setup and tear down functions.
+ * Fixture setup may store things on the clipboard,
+ * the test case may access them and the tear down destroy them.
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ * @return The LongBowClipBoard for the given LongBowTestCase.
+ */
+LongBowClipBoard *longBowTestRunner_GetClipBoard(const LongBowTestRunner *testRunner);
+
+/**
+ * Place a value on the Test Runner "clipboard"
+ *
+ * Every Test Runner has an associated "clipboard" which is shared between the Test Runner
+ * Setup and Test Runner Tear Down and is accessible to all Test Fixtures and Test Cases.
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ * @param [in] shared The value to share on the clipboard.
+ * @return True if the value was set.
+ */
+bool longBowTestRunner_SetClipBoardData(const LongBowTestRunner *testRunner, void *shared);
+
+/**
+ * Get the clipboard data from the given `LongBowTestRunner`.
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ */
+void *longBowTestRunner_GetClipBoardData(const LongBowTestRunner *testRunner);
+
+/**
+ * Execute a LongBow Test Runner.
+ *
+ * The Test Runner will have zero or more Test Fixtures executed in the order
+ * they are specified in the Test Runner function.
+ * See LONGBOW_TEST_RUNNER()
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ * @return The given LongBowTestRunner
+ */
+LongBowTestRunner *longBowTestRunner_Run(LongBowTestRunner *testRunner);
+
+/**
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ * @return An allocated, nul-terminated C string that must be deallocated via free(3)
+ */
+char *longBowTestRunner_ToString(const LongBowTestRunner *testRunner);
+
+/**
+ * Add the supplied LongBowTestFixture to the list of Test Fixtures for the given Test Runner.
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ * @param [in] testFixture A pointer to a valid LongBowTestFixture instance.
+ */
+void longBowTestRunner_AddFixture(LongBowTestRunner *testRunner, LongBowTestFixture *testFixture);
+
+/**
+ * Get the number of Test Fixtures in the given Test Runner.
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ * @return the number of Test Fixtures in the given Test Runner.
+ */
+size_t longBowTestRunner_GetFixtureCount(const LongBowTestRunner *testRunner);
+
+/**
+ * Get a pointer to the Test Fixture indexed by <code>index</code> in this Test Runner.
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ * @param [in] index The index of the LongBowTestFixture to get.
+ * @return The corresponding LongBowTestFixture.
+ */
+LongBowTestFixture *longBowTestRunner_GetFixture(const LongBowTestRunner *testRunner, size_t index);
+
+/**
+ * Get the status of the given LongBow Test Fixture.
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ * @return The LongBowStatus of the given LongBowTestRunner
+ */
+LongBowStatus longBowTestRunner_GetStatus(const LongBowTestRunner *testRunner);
+
+/**
+ * Get a pointer to the LongBowConfig structure for the given Test Runner.
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ * @return A pointer to the LongBowConfig structure for the given runner.
+ */
+LongBowConfig *longBowTestRunner_GetConfiguration(const LongBowTestRunner *testRunner);
+
+/**
+ * Return `true` if the given Test Runner was successful.
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ * @return true if the status of the LongBowTestRunner was successful.
+ */
+bool longBowTestRunner_IsSuccessful(const LongBowTestRunner *testRunner);
+
+/**
+ * Return `true` if the given Test Runner was a failure.
+ *
+ * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+ * @return true if the status of the LongBowTestRunner is as a failure.
+ */
+bool longBowTestRunner_IsFailed(const LongBowTestCase *testCase);
+
+/**
+ * Return `true` if the given Test Runner was a warning.
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ * @return true if the status of the LongBowTestRunner was a warning.
+ */
+bool longBowTestRunner_IsWarning(const LongBowTestRunner *testRunner);
+
+/**
+ * Return `true` if the given Test Runner was incomplete.
+ *
+ * @param [in] testCase A pointer to a valid LongBowTestCase instance.
+ * @return true if the status of the LongBowTestRunner was incomplete.
+ */
+bool longBowTestRunner_IsIncomplete(const LongBowTestCase *testCase);
+
+/**
+ * Get the LongBowClipBoard for the given LongBowTestRunner.
+ *
+ * Every LongBow test runner has an associated "clipboard" that is specific to a test runner
+ * and is shared between the runner setup and tear down functions.
+ * The Test Runner setup may store things on the clipboard,
+ * the test fixtures and test cases may access them and the test runner tear down destroy them.
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ * @return The LongBowClipBoard for the given LongBowTestRunner.
+ */
+LongBowClipBoard *longBowTestRunner_GetClipBoard(const LongBowTestRunner *testRunner);
+
+/**
+ * Set the configuration for the given LongBowTestRunner.
+ *
+ * The <code>LongBowConfig</code> pointed to by <code>configuration</code> is borrowed.
+ * If it is deallocated, reused, or overwritten results are unpredicable.
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ * @param [in] configuration A pointer to a valid LongBowConfig instance.
+ */
+void longBowTestRunner_SetConfiguration(LongBowTestRunner *testRunner, LongBowConfig *configuration);
+
+/**
+ * Get the clipboard data from the given `LongBowTestRunner`.
+ *
+ * @param [in] testRunner A pointer to a valid LongBowTestRunner instance.
+ */
+void *longBowTestRunner_GetClipBoardData(const LongBowTestRunner *testRunner);
+
+/**
+ * Update the LongBowConfig instance with information indicated by @p parameter.
+ *
+ * @param [in] config A pointer to a valid LongBowConfig instance.
+ * @param [in] parameter A pointer to nul-terminated C string.
+ *
+ * @return true A valid parameter.
+ * @return false The value of @p parameter is invalid.
+ */
+bool longBowTestRunner_Config(LongBowConfig *config, const char *parameter);
+
+/**
+ * Print command line and configuration help applicable to a Long Bow Test Runner.
+ *
+ */
+void longBowTestRunner_ConfigHelp(void);
+#endif /* LONGBOWRUNNER_H_ */
diff --git a/longbow/src/LongBow/longBow_UnitTest.h b/longbow/src/LongBow/longBow_UnitTest.h
new file mode 100755
index 00000000..340c6fd1
--- /dev/null
+++ b/longbow/src/LongBow/longBow_UnitTest.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 longBow_UnitTest.h
+ * @ingroup testing
+ * @brief Unit Testing Support.
+ *
+ */
+#ifndef __LongBow__longBow_UnitTest__
+#define __LongBow__longBow_UnitTest__
+
+/**
+ * Compose the C function name prefix for a Test Runner.
+ *
+ * @param [in] _testRunnerName_ A valid identifier for the Test Runner.
+ */
+#define longBowUnitTest_RunnerName(_testRunnerName_) \
+ LongBowTestRunner_ ## _testRunnerName_
+
+/**
+ * Compose the C function name for a Test Runner Setup function.
+ *
+ * @param [in] _testRunnerName_ A valid identifier for the Test Runner.
+ */
+#define longBowUnitTest_RunnerSetupName(_testRunnerName_) \
+ LongBowTestRunner_ ## _testRunnerName_ ## _Setup
+
+/**
+ * @brief Compose the C function name for a Test Runner Tear-Down function.
+ *
+ * @param [in] _testRunnerName_ A valid identifier for the Test Runner.
+ */
+#define longBowUnitTest_RunnerTearDownName(_testRunnerName_) \
+ LongBowTestRunner_ ## _testRunnerName_ ## _TearDown
+
+/**
+ * @brief Compose the C function name for a Test Runner function.
+ *
+ * @param [in] _testRunnerName_ A valid identifier for the Test Runner.
+ */
+#define longBowUnitTest_RunnerRunName(_testRunnerName_) \
+ LongBowTestRunner_ ## _testRunnerName_ ## _Run
+
+/**
+ * @defined longBowUnitTest_FixtureName
+ * @brief Compose a Test Fixture name.
+ * @param [in] _testFixtureName_ A valid identifier fragment for the Test Fixture.
+ */
+#define longBowUnitTest_FixtureName(_testFixtureName_) \
+ LongBowTestFixture_ ## _testFixtureName_
+
+/**
+ * @brief Compose the C function name for a Test Fixture function.
+ *
+ * @param [in] _testFixtureName_ A valid identifier for the Test Fixture.
+ */
+#define longBowUnitTest_FixtureRunName(_testFixtureName_) \
+ LongBowTestFixture_ ## _testFixtureName_ ## _Run
+
+/**
+ * Compose the C function name for a Test Fixture Setup function.
+ *
+ * @param [in] _testFixtureName_ A valid identifier for the Test Fixture.
+ */
+#define longBowUnitTest_FixtureSetupName(_testFixtureName_) \
+ LongBowTestFixture_ ## _testFixtureName_ ## _Setup
+
+/**
+ * @brief Compose the C function name for a Test Fixture Tear-Down function.
+ *
+ * @param [in] _testFixtureName_ A valid identifier for the Test Fixture.
+ */
+#define longBowUnitTest_FixtureTearDownName(_testFixtureName_) \
+ LongBowTestFixture_ ## _testFixtureName_ ## _TearDown
+
+/**
+ * @brief Compose the C name for a Test Fixture Configuration structure.
+ *
+ * @param [in] _testFixtureName_ A valid identifier for the Test Fixture.
+ */
+#define longBowUnitTest_FixtureConfigName(_testFixtureName_) \
+ LongBowTestFixture_ ## _testFixtureName_ ## _Config
+
+/**
+ *
+ */
+#define longBowUnitTest_CaseName(_testFixtureName_, _testCaseName_) \
+ LongBowTestCase_ ## _testFixtureName_ ## _ ## _testCaseName_
+
+#endif /* defined(__LongBow__longBow_UnitTest__) */
diff --git a/longbow/src/LongBow/longBow_UnitTesting.c b/longbow/src/LongBow/longBow_UnitTesting.c
new file mode 100755
index 00000000..a33846ce
--- /dev/null
+++ b/longbow/src/LongBow/longBow_UnitTesting.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 <inttypes.h>
+#include <poll.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/param.h>
+
+#include <LongBow/private/longBow_ArrayList.h>
+#include <LongBow/unit-test.h>
+
+#include <LongBow/longBow_UnitTesting.h>
+
+bool
+longBowUnitTesting_AssertEqualsContract(bool (*equalsFunction)(void *a, void *b), void *x, void *y, void *z, ...)
+{
+ va_list ap;
+ va_start(ap, z);
+
+ assertNotNull(x, "The value of x cannot be NULL.");
+ assertNotNull(y, "The value of y cannot be NULL.");
+ assertNotNull(z, "The value of z cannot be NULL.");
+
+ assertFalse(x == y, "The value x cannot be the same as y");
+ assertFalse(x == z, "The value x cannot be the same as z");
+ assertFalse(y == z, "The value y cannot be the same as z");
+
+ assertTrue(equalsFunction(NULL, NULL), "Equality failed: Equals(NULL, NULL) must be true");
+
+ assertFalse(equalsFunction(x, NULL), "Equality failed: The value of x must not be Equal to NULL.");
+ assertFalse(equalsFunction(NULL, x), "Equality failed: NULL must not be equal to the value of x.");
+
+ assertTrue(equalsFunction(x, x),
+ "Reflexive failed: for any non-null reference value x, equals(x, x) must return true.");
+
+ assertTrue(equalsFunction(x, y),
+ "Equality failed: The values of x and y must be Equal.");
+ assertTrue(equalsFunction(x, z),
+ "Equality failed: The values of x and z must be Equal.");
+
+ assertTrue(equalsFunction(x, y) == equalsFunction(y, x),
+ "Symmetric equality failed: equals(x, y) == equals(y, x) must true.");
+
+ assertTrue((equalsFunction(x, y) == equalsFunction(y, z)) == equalsFunction(z, x),
+ "Transitive equality failed: equals(x, y) == equals(y, z) == equals(z, x) must true.");
+
+ int index = 0;
+ for (void *value = va_arg(ap, void *); value != 0; value = va_arg(ap, void *)) {
+ assertFalse(equalsFunction(x, value), "Value %d (@%p) must not be equal to x", index, value);
+ assertTrue(equalsFunction(x, value) == equalsFunction(value, x),
+ "Symmetric equality failed: equals(x, value) == equals(value, x) must true.");
+ index++;
+ }
+
+ va_end(ap);
+ return true;
+}
+
+bool
+longBowUnitTesting_AssertCompareToContract(int (*compareTo)(const void *a, const void *b),
+ void *exemplar,
+ void **equivalent,
+ void **lesser,
+ void **greater)
+{
+ assertNotNull(exemplar, "Parameter exemplar must not be NULL");
+ assertNotNull(equivalent, "Parameter equivalent must not be NULL");
+ assertNotNull(lesser, "Parameter less must not be NULL");
+ assertNotNull(greater, "Parameter greater must not be NULL");
+
+ assertTrue(compareTo(NULL, NULL) == 0,
+ "Comparison of null values must be 0.");
+
+ assertTrue(compareTo(exemplar, NULL) > 0,
+ "Comparison of a non-null value to a null value must be > 0.");
+
+ assertTrue(compareTo(NULL, exemplar) < 0,
+ "Comparison of null value to a non-null value must be < 0.");
+
+ assertTrue(compareTo(exemplar, exemplar) == 0,
+ "Comparison of a value to itself must == 0");
+
+ for (int i = 0; equivalent[i] != NULL; i++) {
+ assertTrue(compareTo(exemplar, equivalent[i]) == 0,
+ "Comparison of the value to equivalent[%d] must == 0", i);
+ assertTrue(compareTo(exemplar, equivalent[i]) == -compareTo(equivalent[i], exemplar),
+ "Requires sgn(compareTo(value, equivalent[%d])) == -sgn(equivalent[%d], value)", i, i);
+ }
+ for (int i = 0; lesser[i] != NULL; i++) {
+ assertTrue(compareTo(exemplar, lesser[i]) > 0,
+ "Compare of value to lesser[%d] must be > 0", i);
+ assertTrue(compareTo(exemplar, lesser[i]) == -compareTo(lesser[i], exemplar),
+ "Requires sgn(compareTo(value, lesser[%d])) == -sgn(lesser[%d], value)", i, i);
+ }
+ for (int i = 0; greater[i] != NULL; i++) {
+ assertTrue(compareTo(exemplar, greater[i]) < 0,
+ "Compare to greater[%d] must be > 0", i);
+ assertTrue(compareTo(exemplar, greater[i]) == -compareTo(greater[i], exemplar),
+ "Requires sgn(compareTo(value, greater[%d])) == -sgn(greater[%d], value)", i, i);
+ }
+
+ return true;
+}
diff --git a/longbow/src/LongBow/longBow_UnitTesting.h b/longbow/src/LongBow/longBow_UnitTesting.h
new file mode 100755
index 00000000..b03b2f88
--- /dev/null
+++ b/longbow/src/LongBow/longBow_UnitTesting.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 longBow_UnitTesting.h
+ * @ingroup testing
+ * @brief Unit Testing Support.
+ *
+ */
+#ifndef LongBow_longBow_UnitTesting_h
+#define LongBow_longBow_UnitTesting_h
+
+#include <stdbool.h>
+#include <stdarg.h>
+
+/**
+ * Test a that a function implements the Equals contract.
+ *
+ * The equality function that this evaluates must implement the following equivalence relations on non-null instances:
+ *
+ * * It is reflexive: for any non-null reference value x, equals(x, x) must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y, equals(x, y) must return true if and only if
+ * equals(y x) returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * equals(x, y) returns true and
+ * equals(y, z) returns true,
+ * then equals(x, z) must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple invocations of equals(x, y)
+ * consistently return true or consistently return false.
+ *
+ * * For any non-null reference value x, equals(x, NULL)) must return false.
+ *
+ * @param [in] equalsFunction A pointer to a function that will be called to determine if it conforms to the Equals contract.
+ * @param [in] x A pointer to a value that will be used as the base comparision for remaining parameters.
+ * @param [in] y A pointer to a value that is known to be equal to @p x, but is not @p x.
+ * @param [in] z A pointer to a value that is known to be equal to @p x and to @p y, but is neither @p x nor @p y.
+ * @param [in] ... A NULL terminated list of pointers to values that are known to be not equal to @p x, @p y, or @p z.
+ * @return true if the function conforms to the Equals contract.
+ * @see assertEqualsContract()
+ */
+bool longBowUnitTesting_AssertEqualsContract(bool (*equalsFunction)(void *a, void *b), void *x, void *y, void *z, ...);
+
+/**
+ * Compares instance <code>a</code> with instance <code>b</code> for order.
+ *
+ * The comparison function that this evaluates <i>sgn(a - b)</i> required to return a negative integer,
+ * zero, or a positive integer as <code>a</code> is less than,
+ * equal to, or greater than <code>b</code>.
+ *
+ * The function must ensure that:
+ * <ul>
+ * <li>sgn(compareTo(a, b)) == -sgn(b, a) for all values of a and b.</li>
+ * <li>the relation is transitive: (compareTo(x, y)>0 && compareTo(y, z)>0) implies compareTo(x, z)>0.</li>
+ * <li>compareTo(x, y)== 0 implies that sgn(compareTo(x, z)) == sgn(compareTo(y, z)), for all values of z.</li>
+ * </ul>
+ *
+ * This also stipulates that
+ * <code>compareTo(NULL, NULL)) == 0</code>,
+ * <code>compareTo(not-NULL, NULL)) > 0</code>,
+ * <code>compareTo(NULL, not-NULL)) < 0</code>.
+ *
+ * It is strongly recommended, but not strictly required that relation(compareTo(x, y)==0) == equals(x, y)) is true.
+ * Any module that implements the compareTo function and violates this condition
+ * should clearly indicate this fact.
+ * For example, "Note: this implementation has a natural ordering that is inconsistent with equals."
+ *
+ * @param [in] compareTo A pointer to a function implementing the CompareTo function signature.
+ * @param [in] value The pivotal value under test.
+ * @param [in] equivalent A NULL terminated array of values that are all equivalent to <code>value</code>.
+ * @param [in] lesser A NULL terminated array of values that are all less than <code>value</code>.
+ * @param [in] greater A NULL terminated array of values that are all greater than <code>value</code>.
+ * @return <code>true</code> if the evalutation is successful.
+ * @see assertCompareToContract()
+ */
+bool longBowUnitTesting_AssertCompareToContract(int (*compareTo)(const void *a, const void *b), void *value, void **equivalent, void **lesser, void **greater);
+#endif // LongBow_longBow_UnitTesting_h
diff --git a/longbow/src/LongBow/private/longBow_ArrayList.c b/longbow/src/LongBow/private/longBow_ArrayList.c
new file mode 100755
index 00000000..91cf02b9
--- /dev/null
+++ b/longbow/src/LongBow/private/longBow_ArrayList.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <stdbool.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include <LongBow/runtime.h>
+#include <LongBow/private/longBow_ArrayList.h>
+#include <LongBow/private/longBow_Memory.h>
+
+struct longbow_array_list {
+ void **array;
+ size_t numberOfElements;
+ size_t limit;
+ void (*destroyElement)(void **elementAddress);
+};
+
+static LongBowArrayList *_longBowArrayList_EnsureRemaining(LongBowArrayList *array, size_t remnant);
+static LongBowArrayList *_longBowArrayList_EnsureCapacity(LongBowArrayList *array, size_t newCapacity);
+
+void
+longBowArrayList_AssertValid(const LongBowArrayList *array)
+{
+ if (array == NULL) {
+ printf("Parameter must be a non-null pointer to a LongBowArrayList instance\n");
+ abort();
+ }
+}
+
+LongBowArrayList *
+longBowArrayList_Add(LongBowArrayList *array, const void *pointer)
+{
+ longBowArrayList_AssertValid(array);
+
+ if (_longBowArrayList_EnsureRemaining(array, 1) == NULL) {
+ return NULL;
+ }
+ array->array[array->numberOfElements++] = (void *) pointer;
+
+ return array;
+}
+
+static size_t
+_longBowArrayList_Remaining(const LongBowArrayList *array)
+{
+ longBowArrayList_AssertValid(array);
+
+ return array->limit - array->numberOfElements;
+}
+
+static LongBowArrayList *
+_longBowArrayList_EnsureCapacity(LongBowArrayList *array, size_t newCapacity)
+{
+ longBowArrayList_AssertValid(array);
+
+ void *newArray = longBowMemory_Reallocate(array->array, newCapacity * sizeof(void *));
+
+ if (newArray == NULL) {
+ return NULL;
+ }
+ array->array = newArray;
+ array->limit = newCapacity;
+
+ return array;
+}
+
+static LongBowArrayList *
+_longBowArrayList_EnsureRemaining(LongBowArrayList *array, size_t remnant)
+{
+ longBowArrayList_AssertValid(array);
+
+ if (_longBowArrayList_Remaining(array) < remnant) {
+ size_t newCapacity = longBowArrayList_Length(array) + remnant;
+ return _longBowArrayList_EnsureCapacity(array, newCapacity);
+ }
+ return array;
+}
+
+bool
+longBowArrayList_Equals(const LongBowArrayList *a, const LongBowArrayList *b)
+{
+ if (a != b) {
+ if (a == NULL || b == NULL) {
+ return false;
+ }
+ if (a->numberOfElements == b->numberOfElements) {
+ for (size_t i = 0; i < a->numberOfElements; i++) {
+ if (a->array[i] != b->array[i]) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+void *
+longBowArrayList_Get(const LongBowArrayList *array, size_t index)
+{
+ longBowArrayList_AssertValid(array);
+
+ assert(index < array->numberOfElements);
+
+ return array->array[index];
+}
+
+size_t
+longBowArrayList_Length(const LongBowArrayList *array)
+{
+ longBowArrayList_AssertValid(array);
+
+ return array->numberOfElements;
+}
+
+LongBowArrayList *
+longBowArrayList_Create(void (*destroyElement)(void **elementAddress))
+{
+ LongBowArrayList *result = longBowMemory_Allocate(sizeof(LongBowArrayList));
+
+ if (result != NULL) {
+ result->numberOfElements = 0;
+ result->limit = 0;
+ result->array = NULL;
+ result->destroyElement = destroyElement;
+ }
+
+ return result;
+}
+
+LongBowArrayList *
+longBowArrayList_Create_Capacity(void (*destroyElement)(void **elementAddress), size_t size)
+{
+ LongBowArrayList *result = longBowArrayList_Create(destroyElement);
+ if (result != NULL) {
+ _longBowArrayList_EnsureRemaining(result, size);
+ }
+
+ return result;
+}
+
+void
+longBowArrayList_Destroy(LongBowArrayList **arrayPtr)
+{
+ assertNotNull(arrayPtr, "Parameter must be a non-null pointer to a LongBow_ArrayList pointer.");
+
+ LongBowArrayList *array = *arrayPtr;
+
+ longBowArrayList_AssertValid(array);
+
+ assertTrue(array->numberOfElements == 0 ? true : array->array != NULL, "LongBow_ArrayList is inconsistent.");
+
+ if (array->destroyElement != NULL) {
+ for (size_t i = 0; i < array->numberOfElements; i++) {
+ array->destroyElement(&array->array[i]);
+ array->array[i] = NULL;
+ }
+ }
+
+ if (array->array != NULL) {
+ longBowMemory_Deallocate((void **) &array->array);
+ }
+
+ longBowMemory_Deallocate((void **) arrayPtr);
+}
+
+void **
+longBowArrayList_GetArray(const LongBowArrayList *array)
+{
+ longBowArrayList_AssertValid(array);
+ return array->array;
+}
+
+LongBowArrayList *
+longBowArrayList_Copy(const LongBowArrayList *original)
+{
+ longBowArrayList_AssertValid(original);
+
+ LongBowArrayList *result = longBowMemory_Allocate(sizeof(LongBowArrayList));
+
+ if (result != NULL) {
+ for (size_t i = 0; i < original->numberOfElements; i++) {
+ longBowArrayList_Add(result, original->array[i]);
+ }
+ }
+
+ return result;
+}
+
+void
+longBowArrayList_StdlibFreeFunction(void **elementPtr)
+{
+ if (elementPtr != NULL) {
+ free(*elementPtr);
+ *elementPtr = 0;
+ }
+}
+
+LongBowArrayList *
+longBowArrayList_RemoveAtIndex(LongBowArrayList *array, size_t index)
+{
+ longBowArrayList_AssertValid(array);
+
+ size_t length = longBowArrayList_Length(array);
+ assertTrue(index < length, "Index must be ( 0 <= index < %zd). Actual=%zd", length, index);
+
+ if (index < length) {
+ // Destroy the element at the given index.
+ if (array->destroyElement != NULL) {
+ array->destroyElement(&array->array[index]);
+ }
+
+ // Adjust the list to elide the element.
+ for (size_t i = index; i < length; i++) {
+ array->array[i] = array->array[i + 1];
+ }
+ array->numberOfElements--;
+ }
+
+ return array;
+}
+
+LongBowArrayList *
+longBowArrayList_Add_AtIndex(LongBowArrayList *array, const void *pointer, size_t index)
+{
+ longBowArrayList_AssertValid(array);
+ size_t length = longBowArrayList_Length(array);
+
+ if (index > array->limit) {
+ // We need to grow the array to fit this element.
+ _longBowArrayList_EnsureCapacity(array, index + 1);
+ array->numberOfElements = index + 1;
+ } else {
+ // Create space and grow the array if needed
+ _longBowArrayList_EnsureRemaining(array, length + 1);
+ for (size_t i = index; i < length; i++) {
+ array->array[i + 1] = array->array[i];
+ }
+ array->numberOfElements++;
+ }
+
+ array->array[index] = (void *) pointer;
+
+
+ return array;
+}
+
+bool
+longBowArrayList_Replace(LongBowArrayList *array, const void *old, void *new)
+{
+ for (size_t i = 0; i < longBowArrayList_Length(array); i++) {
+ if (array->array[i] == old) {
+ array->array[i] = new;
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/longbow/src/LongBow/private/longBow_ArrayList.h b/longbow/src/LongBow/private/longBow_ArrayList.h
new file mode 100644
index 00000000..71eeb2b9
--- /dev/null
+++ b/longbow/src/LongBow/private/longBow_ArrayList.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 longBow_ArrayList.h
+ * @ingroup internals
+ * @brief A simple, list implementation using a dynamic array.
+ *
+ */
+#ifndef LongBow_ARRAYLIST_H
+#define LongBow_ARRAYLIST_H
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+/**
+ * @struct longbow_array_list
+ * @brief A LongBow_ArrayList is a (dynamic) array of <code>void *</code> pointers;
+ */
+struct longbow_array_list;
+
+/**
+ * @typedef LongBowArrayList
+ * @brief The struct longbow_array_list
+ */
+typedef struct longbow_array_list LongBowArrayList;
+
+/**
+ * Assert that a LongBowArrayList instance is valid.
+ *
+ * @param [in] array A pointer to a valid LongBowArrayList instance.
+ *
+ */
+void longBowArrayList_AssertValid(const LongBowArrayList *array);
+/**
+ * Add a pointer to an element to the given LongBowArrayList.
+ *
+ * If the list was constructed with a destroyer,
+ * the pointer will be destroyed when element is removed or the list is destroyed.
+ *
+ * @param [in] array A pointer to a LongBowArrayList instance.
+ * @param [in] pointer An arbitrary value to store.
+ *
+ * @return The input array pointer.
+ */
+LongBowArrayList *longBowArrayList_Add(LongBowArrayList *array, const void *pointer);
+
+/**
+ * Remove an element at a specific index from an Array List.
+ *
+ * The element is destroyed via the function provided when calling <code>longBowArrayList_Create</code>.
+ *
+ * @param [in] array A pointer to a LongBowArrayList instance.
+ * @param [in] index The index of the element to remove.
+ *
+ * @return A pointer to the modified LongBowArrayList.
+ */
+LongBowArrayList *longBowArrayList_RemoveAtIndex(LongBowArrayList *array, size_t index);
+
+/**
+ * Add an element at the index location. Elements will be moved up if required.
+ * If the index is higher than the current Length the Array will be grown to that size
+ *
+ * @param [in] array A pointer to a LongBowArrayList instance.
+ * @param [in] pointer An arbitrary value to store.
+ * @param [in] index The position that the value will be stored after.
+ * @return A pointer to the modified LongBowArrayList.
+ */
+LongBowArrayList *longBowArrayList_Add_AtIndex(LongBowArrayList *array, const void *pointer, size_t index);
+
+/**
+ * Create an instance of an empty LongBowArrayList.
+ *
+ * @param [in] destroyElement
+ * A pointer to a function that will destroy (or equivalent) the element pointed to by <code>element</code>
+ * @return A pointer to a LongBowArrayList instance, or NULL if no memory could be allocated.
+ */
+LongBowArrayList *longBowArrayList_Create(void (*destroyElement)(void **elementAddress));
+
+/**
+ * Create an instance of a LongBowArrayList pre-provisioned to contain the specified number of elements.
+ *
+ * @param [in] size
+ * The number of initial elements to provision for.
+ * @param [in] destroyElement
+ * A pointer to a function that will destroy (or equivalent) the element pointed to by <code>element</code>
+ * @return A pointer to a LongBowArrayList instance, or NULL if no memory could be allocated.
+ */
+LongBowArrayList *longBowArrayList_Create_Capacity(void (*destroyElement)(void **elementAddress), size_t size);
+
+/**
+ * Get an array of void * pointers.
+ * Return a pointer to an array of void * pointers contained in this Array List.
+ * The returned value may be the actual backing array for the Array List.
+ *
+ * @param [in] array The LongBow_ArrayList
+ * @return A pointer to an array of void * pointers contained in this Array List.
+ *
+ */
+void **longBowArrayList_GetArray(const LongBowArrayList *array);
+
+/**
+ * Copy a LongBowArrayList instance.
+ * Create a new LongBowArrayList instance with the same structure and content as the original.
+ *
+ * @param [in] array A pointer to a LongBowArrayList instance to copy.
+ * @return A pointer to a LongBowArrayList instance with a copy of the original, or NULL if no memory could be allocated.
+ */
+LongBowArrayList *longBowArrayList_Copy(const LongBowArrayList *array);
+
+/**
+ * Destroy a LongBowArrayList instance.
+ *
+ * Destroy the given LongBowArrayList by freeing all memory used by it.
+ *
+ * @param [in,out] arrayPtr A pointer to a LongBowArrayList pointer.
+ */
+void longBowArrayList_Destroy(LongBowArrayList **arrayPtr);
+
+/**
+ * Get an element from the given list at a specified index.
+ * The index must be 0 <= index < length.
+ *
+ * @return A pointer (void *) to the element in the list.
+ *
+ * @param [in] array A pointer to a LongBowArrayList instance.
+ * @param [in] index The index of the required element.
+ */
+void *longBowArrayList_Get(const LongBowArrayList *array, size_t index);
+
+/**
+ * Return the number of elements in the given LongBowArrayList.
+ *
+ * @param [in] array A pointer to a LongBowArrayList instance.
+ * @return A size_t of the number of elements in the given LongBowArrayList.
+ */
+size_t longBowArrayList_Length(const LongBowArrayList *array);
+
+
+/**
+ * Determine if two LongBowArrayList instances are equal.
+ *
+ * Two LongBowArrayList instances are equal if, and only if, they both contain the same pointers in the same order.
+ *
+ * The following equivalence relations on non-null `LongBowArrayList` instances are maintained:
+ *
+ * * It is reflexive: for any non-null reference value x, `LongBowArrayList_Equals(x, x)`
+ * must return true.
+ *
+ * * It is symmetric: for any non-null reference values x and y,
+ * `longBowArrayList_Equals(x, y)` must return true if and only if
+ * `longBowArrayList_Equals(y, x)` returns true.
+ *
+ * * It is transitive: for any non-null reference values x, y, and z, if
+ * `longBowArrayList_Equals(x, y)` returns true and
+ * `longBowArrayList_Equals(y, z)` returns true,
+ * then `longBowArrayList_Equals(x, z)` must return true.
+ *
+ * * It is consistent: for any non-null reference values x and y, multiple
+ * invocations of `longBowArrayList_Equals(x, y)` consistently return true or
+ * consistently return false.
+ *
+ * * For any non-null reference value x, `longBowArrayList_Equals(x, NULL)` must
+ * return false.
+ *
+ * @param a A pointer to a `LongBowArrayList` instance.
+ * @param b A pointer to a `LongBowArrayList` instance.
+ * @return true if the two `LongBowArrayList` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowArrayList *a = longBowArrayList_Create();
+ * LongBowArrayList *b = longBowArrayList_Create();
+ *
+ * if (longBowArrayList_Equals(a, b)) {
+ * // true
+ * } else {
+ * // false
+ * }
+ * }
+ * @endcode
+ */
+
+bool longBowArrayList_Equals(const LongBowArrayList *a, const LongBowArrayList *b);
+
+/**
+ * Standard library free(3) wrapper for use as a destructor function for elements of a LongBowArrayList.
+ *
+ * The create functions for LongBowArrayList have an input parameter that is a pointer to a function that
+ * will be called for each element when the Array List is destroyed, and when an element is removed via longBowArrayList_RemoveAtIndex.
+ * This destroy function has a different calling signature than the standard library's free(3) function.
+ * This function is a wrapper providing the correct facade for the standard library free(3) function.
+ *
+ * @param [in,out] element A pointer to the pointer to an element to be destroyed.
+ */
+void longBowArrayList_StdlibFreeFunction(void **element);
+
+/**
+ * Replace the first occurance of an existing element in the given LongBowArrayList.
+ *
+ * Paragraphs Of Explanation
+ *
+ * @param [in] array A pointer to a LongBowArrayList instance.
+ * @param [in] old A pointer to an element in the list to replace.
+ * @param [in] new A pointer to an element that will replace old.
+ *
+ * @return true If the element was found and replaced.
+ * @return false If the element was not found.
+ */
+bool longBowArrayList_Replace(LongBowArrayList *array, const void *old, void *new);
+#endif // LongBow_ARRAYLIST_H
diff --git a/longbow/src/LongBow/private/longBow_Memory.c b/longbow/src/LongBow/private/longBow_Memory.c
new file mode 100644
index 00000000..1c20101e
--- /dev/null
+++ b/longbow/src/LongBow/private/longBow_Memory.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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <LongBow/private/longBow_Memory.h>
+
+#if HAVE_REALLOC == 0
+static void *
+_LongBow_rplRealloc(void *oldAlloc, size_t newSize)
+{
+ if (newSize == 0) {
+ newSize = 1;
+ }
+
+ char *newAlloc = malloc(newSize);
+
+ if (oldAlloc != NULL) {
+ memcpy(newAlloc, oldAlloc, newSize);
+ free(oldAlloc);
+ }
+ return newAlloc;
+}
+#endif
+
+static uint64_t _outstandingAllocations;
+
+void *
+longBowMemory_Allocate(const size_t size)
+{
+ _outstandingAllocations++;
+ return calloc(1, size);
+}
+
+void *
+longBowMemory_Reallocate(void *oldAllocation, const size_t newSize)
+{
+#if HAVE_REALLOC
+ void *result = realloc(oldAllocation, newSize);
+#else
+ void *result = _LongBow_rplRealloc(oldAllocation, newSize);
+#endif
+
+ if (oldAllocation == NULL) {
+ _outstandingAllocations++;
+ }
+
+ return result;
+}
+
+void
+longBowMemory_Deallocate(void **pointerPointer)
+{
+ free(*pointerPointer);
+ _outstandingAllocations--;
+ *pointerPointer = NULL;
+}
+
+uint64_t
+longBowMemory_OutstandingAllocations(void)
+{
+ return _outstandingAllocations;
+}
+
+char *
+longBowMemory_StringCopy(const char *string)
+{
+ char *result = NULL;
+
+ if (string != NULL) {
+ size_t length = strlen(string);
+ result = longBowMemory_Allocate(length + 1);
+ strcpy(result, string);
+ result[length] = 0;
+ }
+ return result;
+}
diff --git a/longbow/src/LongBow/private/longBow_Memory.h b/longbow/src/LongBow/private/longBow_Memory.h
new file mode 100755
index 00000000..173491dc
--- /dev/null
+++ b/longbow/src/LongBow/private/longBow_Memory.h
@@ -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.
+ */
+
+/**
+ * @file longBow_Memory.c
+ * @ingroup internal
+ * @brief Memory allocation and deallocation support.
+ *
+ */
+#ifndef LongBow_longBow_Memory_h
+#define LongBow_longBow_Memory_h
+
+#include <stdint.h>
+
+/**
+ * Allocate `size` bytes of memory.
+ *
+ * @param [in] size The number of bytes to allocate
+ *
+ * @return non-NULL A pointer to allocated memory that must be deallocated via `longBowMemory_Deallocate`
+ * @return NULL Memory could not be allocated.
+ * @see longBowMemory_Deallocate
+ */
+void *longBowMemory_Allocate(const size_t size);
+
+/**
+ * Reallocate memory adjusting to a new size.
+ *
+ * @param [in] oldAllocation A pointer to memory previously allocated by `longBowMemory_Allocate` or `longBowMemory_Reallocate`
+ * @param [in] newSize The number of bytes to allocate
+ *
+ * @return non-NULL A pointer to allocated memory that must be deallocated via `longBowMemory_Deallocate`
+ * @return NULL Memory could not be allocated.
+ * @see longBowMemory_Allocate
+ */
+void *longBowMemory_Reallocate(void *oldAllocation, const size_t newSize);
+
+/**
+ * Deallocate previously allocated memory.
+ *
+ * @param [in,out] pointerPointer A pointer to a pointer to allocated memory that will set to NULL.
+ *
+ * @see longBowMemory_Allocate
+ */
+void longBowMemory_Deallocate(void **pointerPointer);
+
+/**
+ * Duplicate a nul-terminated C string in allocated memory.
+ *
+ * @param [in] string The nul-terminated string to duplicate
+ *
+ * @return non-NULL A pointer to allocated memory that must be deallocated via `longBowMemory_Deallocate`
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * char *copy = longBowMemory_StringCopy("Hello World");
+ *
+ * longBowMemory_Deallocate((void **) &copy);
+ * }
+ * @endcode
+ *
+ * @see longBowMemory_Deallocate
+ */
+char *longBowMemory_StringCopy(const char *string);
+
+/**
+ * Get the count of outstanding memory allocations.
+ *
+ * @return The number of outstanding memory allocations.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+uint64_t longBowMemory_OutstandingAllocations(void);
+#endif
diff --git a/longbow/src/LongBow/private/longBow_OpenFile.c b/longbow/src/LongBow/private/longBow_OpenFile.c
new file mode 100644
index 00000000..6b82069f
--- /dev/null
+++ b/longbow/src/LongBow/private/longBow_OpenFile.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <inttypes.h>
+#include <stdlib.h>
+#include <poll.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <string.h>
+
+#include <LongBow/private/longBow_OpenFile.h>
+#include <LongBow/private/longBow_Memory.h>
+#include <LongBow/private/longBow_String.h>
+
+struct longbow_openfile {
+ char *fullPathName;
+ struct stat statbuf;
+ int fd;
+};
+
+#if defined(_WIN64)
+static char *
+_getFullPathNameFromFd(int fd)
+{
+ return strdup("./");
+}
+#elif defined(_WIN32)
+static char *
+_getFullPathNameFromFd(int fd)
+{
+ return strdup("./");
+}
+#elif defined(__APPLE__)
+static char *
+_getFullPathNameFromFd(int fd)
+{
+ char filePath[PATH_MAX];
+
+ if (fcntl(fd, F_GETPATH, filePath) != -1) {
+ return strdup(filePath);
+ }
+ return NULL;
+}
+#elif defined(__linux)
+static char *
+_getFullPathNameFromFd(int fd)
+{
+ return strdup("./");
+}
+#elif defined(__unix) // all unices not caught above
+static char *
+_getFullPathNameFromFd(int fd)
+{
+ return strdup("./");
+}
+#elif defined(__posix)
+static char *
+_getFullPathNameFromFd(int fd)
+{
+ return strdup("./");
+}
+#endif
+
+LongBowOpenFile *
+longBowOpenFile_Create(int fd)
+{
+ LongBowOpenFile *result = longBowMemory_Allocate(sizeof(LongBowOpenFile));
+ if (result != NULL) {
+ result->fd = fd;
+
+ if (fstat(fd, &result->statbuf) == 0) {
+ result->fullPathName = _getFullPathNameFromFd(fd);
+ }
+ }
+ return result;
+}
+
+void
+longBowOpenFile_Destroy(LongBowOpenFile **openFilePtr)
+{
+ longBowMemory_Deallocate((void **) openFilePtr);
+}
+
+char *
+longBowOpenFile_StructStatToString(const struct stat *statbuf)
+{
+ LongBowString *string = longBowString_CreateFormat("0x%" PRIx16 " %3ld %10d %10d %6lld",
+ statbuf->st_mode,
+ (long) statbuf->st_nlink,
+ statbuf->st_uid,
+ statbuf->st_gid,
+ (long long) statbuf->st_size);
+ char *result = longBowString_ToString(string);
+
+ return result;
+}
+
+char *
+longBowOpenFile_ToString(LongBowOpenFile *openFile)
+{
+ char *statString = longBowOpenFile_StructStatToString(&(openFile->statbuf));
+ LongBowString *string = longBowString_CreateFormat("%d %s %s", openFile->fd, statString, openFile->fullPathName);
+ free(statString);
+ char *result = longBowString_ToString(string);
+
+ return result;
+}
+
+LongBowArrayList *
+longBowOpenFile_CurrentlyOpen(void)
+{
+ struct rlimit rlimit;
+
+ bool success = getrlimit(RLIMIT_NOFILE, &rlimit) == 0;
+ if (!success) {
+ return NULL;
+ }
+ // Here is a potential problem: struct rlimit specifies rlim_cur as a 64 bit value (rlim_t), but poll only takes an
+ // unsigned int's worth of file descriptors.
+
+ LongBowArrayList *list = longBowArrayList_Create(longBowArrayList_StdlibFreeFunction);
+
+ for (nfds_t i = 0; i < (nfds_t) rlimit.rlim_cur; i++) {
+ int flags = fcntl((int) i, F_GETFD);
+ if (flags != -1) {
+ LongBowOpenFile *openFile = longBowOpenFile_Create((int) i);
+ longBowArrayList_Add(list, openFile);
+ }
+ }
+
+ return list;
+}
diff --git a/longbow/src/LongBow/private/longBow_OpenFile.h b/longbow/src/LongBow/private/longBow_OpenFile.h
new file mode 100755
index 00000000..10756ba5
--- /dev/null
+++ b/longbow/src/LongBow/private/longBow_OpenFile.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 longBow_OpenFile.h
+ * @ingroup testing
+ * @brief LongBow support for files and file descriptors.
+ *
+ */
+#ifndef LongBow_longBow_Files_h
+#define LongBow_longBow_Files_h
+
+#include <sys/stat.h>
+
+#include <LongBow/private/longBow_ArrayList.h>
+
+struct longbow_openfile;
+/**
+ * @typedef LongBowOpenFile
+ * @brief A representation of an open file.
+ */
+typedef struct longbow_openfile LongBowOpenFile;
+
+/**
+ * @param [in] fd The file descriptor.
+ * @return An allocated LongBowOpenFile instance that must be destroyed via longBowOpenFile_Destroy().
+ */
+LongBowOpenFile *longBowOpenFile_Create(int fd);
+
+/**
+ *
+ * @param [in,out] openFilePtr A pointer to a pointer to a valid LongBowOpenFile instance.
+ */
+void longBowOpenFile_Destroy(LongBowOpenFile **openFilePtr);
+
+/**
+ *
+ * @param [in] openFile A pointer to a valid LongBowOpenFile instance.
+ * @return A nul-terminate C string that must be freed via free(3).
+ */
+char *longBowOpenFile_ToString(LongBowOpenFile *openFile);
+
+/**
+ * Create a list of the currently open files.
+ *
+ * @return A list of LongBowOpenFile instances for each open file.
+ */
+LongBowArrayList *longBowOpenFile_CurrentlyOpen(void);
+
+/**
+ * Return a nul-terminated C string representing the given `struct stat` pointed to by @p statbuf.
+ *
+ * @param [in] statbuf A pointer to a valid `struct stat` instance.
+ *
+ * @return non-NULL A nul-terminated C string that must be deallocated via longBowMemory_Deallocate.
+ */
+char *longBowOpenFile_StructStatToString(const struct stat *statbuf);
+#endif
diff --git a/longbow/src/LongBow/private/longBow_String.c b/longbow/src/LongBow/private/longBow_String.c
new file mode 100644
index 00000000..1def87a1
--- /dev/null
+++ b/longbow/src/LongBow/private/longBow_String.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 <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <LongBow/private/longBow_String.h>
+#include <LongBow/private/longBow_Memory.h>
+
+struct longbow_string {
+ char *buffer;
+ size_t cursor; // always the index of the nul terminating byte of the stored string.
+ size_t end; // always the index of the very last byte in buffer;
+};
+
+static size_t
+_longBowString_RemainingSpace(const LongBowString *string)
+{
+ size_t result = string->end - string->cursor;
+
+ return result;
+}
+
+LongBowString *
+longBowString_Create(const size_t initialSize)
+{
+ LongBowString *result = longBowMemory_Allocate(sizeof(LongBowString));
+ result->end = initialSize;
+ result->buffer = longBowMemory_Allocate(initialSize);
+ result->cursor = 0;
+
+ return result;
+}
+
+LongBowString *
+longBowString_CreateString(const char *string)
+{
+ LongBowString *result = longBowMemory_Allocate(sizeof(LongBowString));
+ result->end = strlen(string) + 1;
+ result->buffer = longBowMemory_StringCopy(string);
+ result->cursor = result->end - 1;
+ result->buffer[result->cursor] = 0;
+
+ return result;
+}
+
+LongBowString *
+longBowString_CreateFormat(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ char *cString;
+ if (vasprintf(&cString, format, ap) == -1) {
+ return NULL;
+ }
+ va_end(ap);
+
+ LongBowString *string = longBowString_CreateString(cString);
+
+ free(cString);
+
+ return string;
+}
+
+void
+longBowString_Destroy(LongBowString **stringPtr)
+{
+ LongBowString *string = *stringPtr;
+ if (string != NULL) {
+ longBowMemory_Deallocate((void **) &string->buffer);
+ longBowMemory_Deallocate((void **) stringPtr);
+ }
+}
+
+LongBowString *
+longBowString_Append(LongBowString *string, const char *value)
+{
+ size_t length = strlen(value) + 1;
+
+ if (_longBowString_RemainingSpace(string) < length) {
+ size_t size = string->end + length;
+ string->buffer = longBowMemory_Reallocate(string->buffer, size);
+ string->end = size - 1;
+ }
+ strcpy(&string->buffer[string->cursor], value);
+ string->cursor += (length - 1);
+ string->buffer[string->cursor] = 0;
+
+ return string;
+}
+
+LongBowString *
+longBowString_Format(LongBowString *string, const char *format, ...)
+{
+ LongBowString *result = NULL;
+
+ va_list ap;
+ va_start(ap, format);
+
+ char *cString;
+ int status = vasprintf(&cString, format, ap);
+ va_end(ap);
+ if (status != -1) {
+ result = longBowString_Append(string, cString);
+ free(cString);
+ } else {
+ result = NULL;
+ }
+
+ return result;
+}
+
+char *
+longBowString_ToString(const LongBowString *string)
+{
+ char *result = strndup(string->buffer, string->end);
+ return result;
+}
+
+bool
+longBowString_StartsWith(const char *string, const char *prefix)
+{
+ bool result = strncmp(string, prefix, strlen(prefix)) == 0;
+ return result;
+}
+
+bool
+longBowString_Equals(const char *string, const char *other)
+{
+ return strcmp(string, other) == 0;
+}
+
+bool
+longBowString_Write(const LongBowString *string, FILE *fp)
+{
+ bool result = false;
+ size_t nwrite = string->end;
+
+ if (fwrite(string->buffer, sizeof(char), string->end, fp) == nwrite) {
+ result = true;
+ }
+
+ return result;
+}
+
+LongBowArrayList *
+longBowString_Tokenise(const char *string, const char *separators)
+{
+ LongBowArrayList *result = longBowArrayList_Create(longBowMemory_Deallocate);
+ if (string != NULL) {
+ char *workingCopy = longBowMemory_StringCopy(string);
+
+ char *p = strtok(workingCopy, separators);
+ while (p) {
+ longBowArrayList_Add(result, longBowMemory_StringCopy(p));
+ p = strtok(NULL, separators);
+ }
+
+ longBowMemory_Deallocate((void **) &workingCopy);
+ }
+
+ return result;
+}
diff --git a/longbow/src/LongBow/private/longBow_String.h b/longbow/src/LongBow/private/longBow_String.h
new file mode 100755
index 00000000..463dfbd8
--- /dev/null
+++ b/longbow/src/LongBow/private/longBow_String.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 longBow_String.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef __LongBow__longBow_String__
+#define __LongBow__longBow_String__
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <LongBow/private/longBow_ArrayList.h>
+
+struct longbow_String;
+typedef struct longbow_string LongBowString;
+
+/**
+ * Create a LongBowString
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] initialSize The initial buffer size to allocate for the string.
+ *
+ * @return non-NULL A pointer to a valid LongBowString instance.
+ * @return NULL Memory could not be allocated.
+ *
+ */
+LongBowString *longBowString_Create(const size_t initialSize);
+
+/**
+ * Create a `LongBowString` instance containing the formatted result of the given format string and parameters.
+ *
+ * @param [in] format A pointer to a valid LongBowString instance.
+ *
+ * @return The a LongBowString instance that must be deallocated via longBowString_Deallocate.
+ */
+LongBowString *longBowString_CreateFormat(const char *format, ...) __attribute__((format(printf, 1, 2)));
+
+/**
+ * Destroy a LongBowString instance.
+ *
+ * The pointer will be set to zero on return.
+ *
+ * @param [in,out] stringPtr A pointer to a valid LongBowString instance.
+ */
+void longBowString_Destroy(LongBowString **stringPtr);
+
+/**
+ * Append to the given LongBowString instance the formatted result of the given format string and parameters.
+ *
+ * @param [in] string A pointer to a valid LongBowString instance.
+ *
+ * @return The value of @p string
+ */
+LongBowString *longBowString_Format(LongBowString *string, const char *format, ...) __attribute__((format(printf, 2, 3)));
+
+/**
+ * Determine if a string begins with a specific prefix.
+ *
+ * @param [in] string A nul-terminated C string.
+ * @param [in] prefix A nul-terminated C string.
+ *
+ * @return true The value of @p string starts with @p prefix.
+ * @return false The value of @p string does not start with @p prefix.
+ *
+ * Example:
+ * @code
+ * {
+ * bool result = longBowString_StartsWith("Hello World", "Hello");
+ * }
+ * @endcode
+ */
+bool longBowString_StartsWith(const char *string, const char *prefix);
+
+/**
+ * Determine if a nul-terminated C string is equal to another.
+ *
+ * @param [in] string A nul-terminated C string.
+ * @param [in] other A nul-terminated C string.
+ *
+ * @return true The value of @p string starts with @p prefix.
+ * @return false The value of @p string does not start with @p prefix.
+ *
+ * Example:
+ * @code
+ * {
+ * bool result = longBowString_StartsWith("Hello World", "Hello");
+ * }
+ * @endcode
+ */
+bool longBowString_Equals(const char *string, const char *other);
+
+/**
+ * Produce a LongBowArrayList containing the tokens for the given @p string
+ * where each token is separated by characters in the string @p separators.
+ *
+ * @param [in] string A nul-terminated C string.
+ * @param [in] separators A nul-terminated C string containing the characters that separate the tokens.
+ *
+ * @return non-NULL A valid LongBowArrayList containing the tokens of the string.
+ * @return NULL Memory could not be allocated.
+ *
+ * Example:
+ * @code
+ * {
+ * LongBowArrayList *result = longBowString_Tokenise("Hello World", " ");
+ * ....
+ * longBowArrayList_Destroy(&result);
+ * }
+ * @endcode
+ */
+LongBowArrayList *longBowString_Tokenise(const char *string, const char *separators);
+
+/**
+ * Produce a nul-terminated C string from the given LongBowString instance.
+ *
+ * @param [in] string A pointer to a valid LongBowString instance.
+ *
+ * @return non-NULL A pointer to a nul-terminated C string that must be deallocated via free(3).
+ */
+char *longBowString_ToString(const LongBowString *string);
+
+/**
+ * Write the contents of the given LongBowString instance to the specified FILE output stream.
+ *
+ * @param [in] string A pointer to a valid LongBowString instance.
+ * @param [in] fp A pointer to a valid FILE instance.
+ *
+ * @return true All of the string was successfully written.
+ * @return false All of the string was not successfully written.
+ */
+bool longBowString_Write(const LongBowString *string, FILE *fp);
+
+#endif /* defined(__LongBow__longBow_String__) */
diff --git a/longbow/src/LongBow/runtime.h b/longbow/src/LongBow/runtime.h
new file mode 100644
index 00000000..5acd790d
--- /dev/null
+++ b/longbow/src/LongBow/runtime.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 runtime.h
+ * @ingroup runtime
+ * @brief LongBow Runtime Support
+ *
+ */
+#ifndef LongBow_runtime_h
+#define LongBow_runtime_h
+
+#include <signal.h>
+
+#include <LongBow/longBow_Runtime.h>
+
+/**
+ * @def longBowIsFalse
+ * @brief Indicate true if a condition is false.
+ *
+ * @param [in] condition The condition to test.
+ */
+#if __GNUC__
+# define longBowIsFalse(condition) __builtin_expect(!(condition), 0)
+#else
+# define longBowIsFalse(condition) (!(condition))
+#endif
+
+#if __STDC_VERSION__ < 199901L
+# define __func__ ((const char *) 0)
+#endif
+
+/**
+ * @def longBowEvent
+ * @brief If the condition is true record the given event and abort the running programme.
+ *
+ * @param [in] eventPointer
+ * @param [in] condition A boolean value that is expected to be true.
+ * @param [in] location A pointer to a LongBowLocation instance.
+ * @param [in] ... A printf format string following corresponding parameters.
+ */
+#ifdef LongBow_DISABLE_ASSERTIONS
+#define longBowEvent(eventPointer, condition, location, ...) if (0 && condition) for (; false; )
+#else
+#define longBowEvent(eventPointer, condition, location, ...) \
+ if (longBowRuntime_EventEvaluation(eventPointer) && longBowIsFalse(condition) && \
+ longBowRuntime_EventTrigger(eventPointer, location, #condition, __VA_ARGS__)) \
+ for (; true; longBowRuntime_Abort(), kill(0, SIGTRAP))
+#endif
+
+/**
+ * @def longBowAssert
+ * @brief Assert a condition, abort the running programme recording the given event if the condition is false.
+ *
+ * @param [in] eventPointer
+ * @param [in] condition A boolean value that is expected to be true.
+ * @param [in] ... A printf format string following corresponding parameters.
+ */
+
+# define longBowAssert(eventPointer, condition, ...) \
+ longBowEvent(eventPointer, condition, longBowLocation_Create(__FILE__, __func__, __LINE__), __VA_ARGS__)
+
+/**
+ * @def longBowTrap
+ * @brief Abort the running programme recording the given trap.
+ *
+ * @param [in] eventPointer
+ * @param [in] ... A printf format string following corresponding parameters.
+ */
+#define longBowTrap(eventPointer, ...) \
+ longBowRuntime_EventEvaluation(eventPointer); \
+ if (longBowRuntime_EventTrigger(eventPointer, \
+ longBowLocation_Create(__FILE__, __func__, __LINE__), longBowEventType_GetName(eventPointer), __VA_ARGS__), true) \
+ for (; true; abort())
+
+
+#define longBowTrapIf(eventPointer, condition, ...) \
+ longBowEvent(eventPointer, (!(condition)), longBowLocation_Create(__FILE__, __func__, __LINE__), __VA_ARGS__)
+
+/**
+ * @def longBowTest
+ * @brief Terminate a LongBow Test Case signaling the given event if the condition is false.
+ *
+ * @param [in] testEventPointer
+ * @param [in] ... A printf format string following corresponding parameters.
+ */
+# define longBowTest(testEventPointer, ...) do { \
+ longBowRuntime_EventEvaluation(testEventPointer); \
+ longBowRuntime_EventTrigger(testEventPointer, \
+ longBowLocation_Create(__FILE__, __func__, __LINE__), \
+ "Test", __VA_ARGS__); \
+ longjmp(longBowTestCaseAbort, SIGABRT); \
+} while (0)
+
+#include <LongBow/assertions.h>
+#include <LongBow/debugging.h>
+#include <LongBow/traps.h>
+#endif // LongBow_runtime_h
diff --git a/longbow/src/LongBow/stubs/execinfo.h b/longbow/src/LongBow/stubs/execinfo.h
new file mode 100755
index 00000000..a6d6d407
--- /dev/null
+++ b/longbow/src/LongBow/stubs/execinfo.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 LongBow_execinfo_h
+#define LongBow_execinfo_h
+
+#define backtrace(...) (1)
+#define backtrace_symbols(...) 0
+#define backtrace_symbols_fd(...) ((void) 0)
+
+#endif // LongBow_execinfo_h
diff --git a/longbow/src/LongBow/test/.gitignore b/longbow/src/LongBow/test/.gitignore
new file mode 100644
index 00000000..182506bc
--- /dev/null
+++ b/longbow/src/LongBow/test/.gitignore
@@ -0,0 +1,30 @@
+*.gcda
+*.gcno
+*.gcov
+*.longbow
+*.log
+test_longBow_ArrayList
+test_longBow_Backtrace
+test_longBow_Config
+test_longBow_Debug
+test_longBow_Fixture
+test_longBow_Memory
+test_longBow_Main
+test_longBow_OpenFile
+test_longBow_Report
+test_longBow_Runner
+test_longBow_Runtime
+test_longBow_Status
+test_longBow_TestCase
+test_longBow_TestCaseClipBoard
+test_longBow_Properties
+test_longBow_UnitTesting
+test_longBow_Empty
+test_longBow_File
+test_longBow_String
+test_longBow_Thread
+test_longBow_CommandLineOptions
+test_longBow_Expected
+test_assertions
+test_longBow_Properties
+test_longBow_MeasureTime
diff --git a/longbow/src/LongBow/test/CMakeLists.txt b/longbow/src/LongBow/test/CMakeLists.txt
new file mode 100644
index 00000000..5eba0444
--- /dev/null
+++ b/longbow/src/LongBow/test/CMakeLists.txt
@@ -0,0 +1,52 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+
+macro(AddTest testFile)
+ add_executable(${ARGV0} ${ARGV0}.c)
+ target_link_libraries(${ARGV0} longbow longbow-ansiterm)
+ add_test(${ARGV0} ${ARGV0})
+ set_target_properties(${ARGV0} PROPERTIES FOLDER Test)
+endmacro(AddTest)
+
+set(TestsExpectedToFail
+ test_longBow_Expected;
+)
+
+# test_assertions;
+
+set(TestsExpectedToPass
+ test_MemoryLeaks;
+ test_longBow_ArrayList;
+ test_longBow_Config;
+ test_longBow_Fixture;
+ test_longBow_Memory;
+ test_longBow_Location;
+ test_fixtureConfiguration;
+ test_longBow_Backtrace;
+ test_longBow_CommandLineOptions;
+ test_longBow_Debug;
+ test_longBow_Main;
+ test_longBow_MeasureTime;
+ test_longBow_OpenFile;
+ test_longBow_Properties;
+ test_longBow_Runner;
+ test_longBow_Runtime;
+ test_longBow_Status;
+ test_longBow_String;
+ test_longBow_TestCase;
+ test_longBow_TestCaseClipBoard;
+ test_longBow_UnitTesting
+ )
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
+foreach(test ${TestsExpectedToFail})
+ AddTest(${test})
+ set_tests_properties(${test} PROPERTIES WILL_FAIL TRUE)
+endforeach()
+
+
diff --git a/longbow/src/LongBow/test/test_MemoryLeaks.c b/longbow/src/LongBow/test/test_MemoryLeaks.c
new file mode 100755
index 00000000..f5eb4160
--- /dev/null
+++ b/longbow/src/LongBow/test/test_MemoryLeaks.c
@@ -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.
+ */
+
+/** *
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <inttypes.h>
+
+#include "../private/longBow_Memory.h"
+
+LONGBOW_TEST_RUNNER(test_MemoryLeaks)
+{
+ // 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_MemoryLeaks)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_MemoryLeaks)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+// LONGBOW_RUN_TEST_CASE(Global, myTest);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, myTest)
+{
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_MemoryLeaks);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ assertTrue(longBowMemory_OutstandingAllocations() == 0, "Memory leaks %" PRId64, longBowMemory_OutstandingAllocations());
+
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_assertions.c b/longbow/src/LongBow/test/test_assertions.c
new file mode 100755
index 00000000..f20d0e5b
--- /dev/null
+++ b/longbow/src/LongBow/test/test_assertions.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/runtime.h>
+#include <stdbool.h>
+
+int
+main(int argc, char *argv[argc])
+{
+ assertTrue(false, "Must fail.");
+}
diff --git a/longbow/src/LongBow/test/test_fixtureConfiguration.c b/longbow/src/LongBow/test/test_fixtureConfiguration.c
new file mode 100755
index 00000000..92023f48
--- /dev/null
+++ b/longbow/src/LongBow/test/test_fixtureConfiguration.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+LONGBOW_TEST_RUNNER(test_fixtureConfiguration)
+{
+ // 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_fixtureConfiguration)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_fixtureConfiguration)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_OPTIONS(Global, .enabled = false)
+{
+ LONGBOW_RUN_TEST_CASE(Global, myTest);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, myTest)
+{
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_fixtureConfiguration);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_ArrayList.c b/longbow/src/LongBow/test/test_longBow_ArrayList.c
new file mode 100644
index 00000000..5ce70885
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_ArrayList.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/testing.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include "../private/longBow_ArrayList.h"
+#include "../private/longBow_Memory.h"
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+LONGBOW_TEST_RUNNER(longBow_ArrayList)
+{
+ // 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(longBow_ArrayList)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(longBow_ArrayList)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, CreateDestroy);
+ LONGBOW_RUN_TEST_CASE(Global, longBowArrayList_Add);
+}
+
+uint64_t _setupAllocations;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ _setupAllocations = longBowMemory_OutstandingAllocations();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint64_t leaks = longBowMemory_OutstandingAllocations() - _setupAllocations;
+ if (leaks != 0) {
+ printf("leaks %" PRId64 " allocations.\n", leaks);
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, CreateDestroy)
+{
+ LongBowArrayList *list = longBowArrayList_Create((void (*)(void **))longBowMemory_Deallocate);
+
+ longBowArrayList_Destroy(&list);
+}
+
+LONGBOW_TEST_CASE(Global, longBowArrayList_Add)
+{
+ LongBowArrayList *list = longBowArrayList_Create((void (*)(void **))longBowMemory_Deallocate);
+
+ char *thing = longBowMemory_StringCopy("name");
+ longBowArrayList_Add(list, thing);
+
+ longBowArrayList_Destroy(&list);
+}
+
+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[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_ArrayList);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_Backtrace.c b/longbow/src/LongBow/test/test_longBow_Backtrace.c
new file mode 100755
index 00000000..40582b85
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_Backtrace.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 "../longBow_Backtrace.h"
+
+#include <stdio.h>
+#include "../testing.h"
+#include <LongBow/private/longBow_Memory.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+LONGBOW_TEST_RUNNER(longBow_Backtrace)
+{
+ // 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(longBow_Backtrace)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Backtrace)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, LongBowBacktrace_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, longBowBacktrace_Create);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, LongBowBacktrace_ToString)
+{
+ LongBowBacktrace *backtrace = longBowBacktrace_Create(100, 0);
+ char *result = longBowBacktrace_ToString(backtrace);
+
+ assertNotNull(result, "Expected non-null result from LongBowBacktrace_ToString()");
+
+ longBowMemory_Deallocate((void **) &result);
+ longBowBacktrace_Destroy(&backtrace);
+}
+
+LONGBOW_TEST_CASE(Global, longBowBacktrace_Create)
+{
+ LongBowBacktrace *backtrace = longBowBacktrace_Create(100, 0);
+ assertNotNull(backtrace, "Expected non-null result from longBowBacktrace_Create()");
+ longBowBacktrace_Destroy(&backtrace);
+ assertNull(backtrace, "Expected LongBowBacktrace_Destroy() to set the pointer to null");
+
+ backtrace = longBowBacktrace_Create(100, 1);
+ longBowBacktrace_Destroy(&backtrace);
+}
+
+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[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Backtrace);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_CommandLineOptions.c b/longbow/src/LongBow/test/test_longBow_CommandLineOptions.c
new file mode 100755
index 00000000..b63375fe
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_CommandLineOptions.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 <stdio.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+LONGBOW_TEST_RUNNER(test_longBow_CommandLineOptions)
+{
+ printf("test_longBow_CommandLineOptions\n");
+
+ // 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(testFixture);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_longBow_CommandLineOptions)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_longBow_CommandLineOptions)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(testFixture)
+{
+ printf(" testFixture\n");
+ LONGBOW_RUN_TEST_CASE(testFixture, testCase);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(testFixture)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(testFixture)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(testFixture, testCase)
+{
+ printf(" testCase\n");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_longBow_CommandLineOptions);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_Config.c b/longbow/src/LongBow/test/test_longBow_Config.c
new file mode 100755
index 00000000..98589d32
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_Config.c
@@ -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.
+ */
+
+#include <LongBow/testing.h>
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <LongBow/longBow_Config.h>
+#include "../private/longBow_Memory.h"
+
+LONGBOW_TEST_RUNNER(longBow_Config)
+{
+ // 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(longBow_Config)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Config)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, CreateDestroy);
+}
+
+uint64_t _setupAllocations;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ _setupAllocations = longBowMemory_OutstandingAllocations();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint64_t leaks = longBowMemory_OutstandingAllocations() - _setupAllocations;
+ if (leaks != 0) {
+ printf("leaks %" PRId64 " allocations.\n", leaks);
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, CreateDestroy)
+{
+ LongBowConfig *config = longBowConfig_Create(0, NULL, NULL);
+
+ longBowConfig_Destroy(&config);
+}
+
+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[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Config);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ if (longBowMemory_OutstandingAllocations() != 0) {
+ printf("%" PRId64 " allocation leaks.", longBowMemory_OutstandingAllocations());
+ }
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_Debug.c b/longbow/src/LongBow/test/test_longBow_Debug.c
new file mode 100755
index 00000000..30805d4a
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_Debug.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 <LongBow/testing.h>
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+LONGBOW_TEST_RUNNER(longBow_Debug)
+{
+ // 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(longBow_Debug)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Debug)
+{
+ 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[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Debug);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_Expected.c b/longbow/src/LongBow/test/test_longBow_Expected.c
new file mode 100755
index 00000000..7b49cb89
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_Expected.c
@@ -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.
+ */
+
+#include <LongBow/testing.h>
+
+LONGBOW_TEST_RUNNER(longBow_Expected)
+{
+ // 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(longBow_Expected)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Expected)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ExpectFailure);
+ LONGBOW_RUN_TEST_CASE(Global, ExpectSuccess);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, ExpectSuccess, .event = &LongBowAssertEvent)
+{
+ assertTrue(false, "This must be successful by failing.");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, ExpectFailure, .event = &LongBowAssertEvent)
+{
+ assertNull(NULL, "This must fail to fail.");
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Expected);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_Fixture.c b/longbow/src/LongBow/test/test_longBow_Fixture.c
new file mode 100644
index 00000000..599b4be5
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_Fixture.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 <stdio.h>
+#include <inttypes.h>
+#include <LongBow/testing.h>
+#include <LongBow/private/longBow_Memory.h>
+
+LONGBOW_TEST_RUNNER(longBow_Fixture)
+{
+ // 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(CreateDestroy);
+ 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(longBow_Fixture)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Fixture)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(CreateDestroy)
+{
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, LongBowTestFixture_Create_Destroy);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateDestroy)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateDestroy)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, LongBowTestFixture_Create_Destroy)
+{
+ uint64_t allocations = longBowMemory_OutstandingAllocations();
+ LongBowTestRunner *runner = longBowTestRunner_Create("runner", NULL, NULL, NULL);
+
+ LongBowTestFixture *fixture = longBowTestFixture_Create(runner, "fixture", NULL, NULL, NULL);
+ assertNotNull(fixture, "Expected non-null result from LongBowTestFixture_Create");
+ longBowTestFixture_Destroy(&fixture);
+ longBowTestRunner_Destroy(&runner);
+ assertTrue(longBowMemory_OutstandingAllocations() == allocations,
+ "Memory leaks %" PRId64, longBowMemory_OutstandingAllocations());
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, longBowTestFixture_GetRunner);
+ LONGBOW_RUN_TEST_CASE(Global, longBowTestFixture_GetClipBoard);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ LongBowTestRunner *runner = longBowTestRunner_Create("testRunner", NULL, NULL, NULL);
+ LongBowTestFixture *fixture = longBowTestFixture_Create(runner, "testFixture", NULL, NULL, NULL);
+
+ longBowClipBoard_Set(testClipBoard, "runner", runner);
+ longBowClipBoard_Set(testClipBoard, "fixture", fixture);
+ longBowTestCase_SetClipBoardData(testCase, fixture);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ LongBowTestFixture *fixture = longBowTestCase_GetClipBoardData(testCase);
+
+ LongBowTestRunner *runner = longBowTestFixture_GetRunner(fixture);
+
+ longBowTestRunner_Destroy(&runner);
+ longBowTestFixture_Destroy(&fixture);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, longBowTestFixture_GetRunner)
+{
+ LongBowTestRunner *xrunner = longBowClipBoard_Get(testClipBoard, "runner");
+ LongBowTestFixture *xfixture = longBowClipBoard_Get(testClipBoard, "fixture");
+ LongBowTestFixture *fixture = longBowTestCase_GetClipBoardData(testCase);
+ LongBowTestRunner *runner = longBowTestFixture_GetRunner(fixture);
+
+ assertTrue(xrunner == runner, "Expected runner to be equal.");
+ assertTrue(xfixture == fixture, "Expected runner to be equal.");
+
+ assertNotNull(runner, "Expected the test runner to not be null");
+}
+
+LONGBOW_TEST_CASE(Global, longBowTestFixture_GetClipBoard)
+{
+ LongBowTestFixture *fixture = longBowTestCase_GetClipBoardData(testCase);
+ LongBowClipBoard *clipboard = longBowTestFixture_GetClipBoard(fixture);
+ assertNotNull(clipboard, "Expected non-null result from longBowTestFixture_GetClipBoard");
+}
+
+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[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Fixture);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_Location.c b/longbow/src/LongBow/test/test_longBow_Location.c
new file mode 100755
index 00000000..9ed77079
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_Location.c
@@ -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.
+ */
+
+#include <LongBow/testing.h>
+
+LONGBOW_TEST_RUNNER(longBow_Location)
+{
+ // 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(longBow_Location)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Location)
+{
+ 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[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Location);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_Main.c b/longbow/src/LongBow/test/test_longBow_Main.c
new file mode 100755
index 00000000..f8be93ed
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_Main.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/testing.h>
+
+LONGBOW_TEST_RUNNER(longBow_Main)
+{
+ // 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(longBow_Main)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Main)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, longBowMain);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, longBowMain)
+{
+ LongBowStatus expected = LONGBOW_STATUS_SUCCEEDED;
+
+ int actual = longBowMain(0, NULL, NULL);
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Main);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_MeasureTime.c b/longbow/src/LongBow/test/test_longBow_MeasureTime.c
new file mode 100644
index 00000000..294c7c60
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_MeasureTime.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../longBow_MeasureTime.c"
+
+#include <stdint.h>
+#include <inttypes.h>
+#include <LongBow/private/longBow_Memory.h>
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(longBow_MeasureTime)
+{
+ // 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(longBow_MeasureTime)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(longBow_MeasureTime)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, longBowMeasureTime_CountDown);
+ LONGBOW_RUN_TEST_CASE(Global, longBowMeasureTime_Report);
+ LONGBOW_RUN_TEST_CASE(Global, longBowMeasureTime_Start);
+ LONGBOW_RUN_TEST_CASE(Global, longBowMeasureTime_Stop);
+ LONGBOW_RUN_TEST_CASE(Global, longBowMeasureTime_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, longBowMeasureTime);
+}
+
+uint64_t _setupAllocations;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ _setupAllocations = longBowMemory_OutstandingAllocations();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint64_t leaks = longBowMemory_OutstandingAllocations() - _setupAllocations;
+ if (leaks != 0) {
+ printf("%s leaks %" PRId64 " allocations.\n", longBowTestCase_GetFullName(testCase), leaks);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, longBowMeasureTime_CountDown)
+{
+ LongBowMeasureTime *measure = longBowMeasureTime_Start(1);
+ assertTrue(measure->iterations == 1, "Expected iterations to be 1, actual %d", measure->iterations);
+
+ longBowMeasureTime_CountDown(measure);
+ assertTrue(measure->iterations == 0, "Expected iterations to be 0, actual %d", measure->iterations);
+
+ longBowMeasureTime_Destroy(&measure);
+}
+
+LONGBOW_TEST_CASE(Global, longBowMeasureTime_Report)
+{
+ LongBowMeasureTime *measure = longBowMeasureTime_Start(1);
+ assertTrue(measure->iterations == 1, "Expected iterations to be 1, actual %d", measure->iterations);
+
+ longBowMeasureTime_Report(measure, __FILE__, __func__, __LINE__);
+
+ longBowMeasureTime_Destroy(&measure);
+}
+
+LONGBOW_TEST_CASE(Global, longBowMeasureTime_Start)
+{
+ LongBowMeasureTime *measure = longBowMeasureTime_Start(1);
+ assertNotNull(measure, "Expected longBowMeasureTime_Start to return non-NULL result.");
+
+ longBowMeasureTime_Destroy(&measure);
+}
+
+LONGBOW_TEST_CASE(Global, longBowMeasureTime_Stop)
+{
+ LongBowMeasureTime *measure = longBowMeasureTime_Start(1);
+ assertNotNull(measure, "Expected longBowMeasureTime_Start to return non-NULL result.");
+ sleep(2);
+ longBowMeasureTime_Stop(measure);
+
+ uint64_t nanos = longBowMeasureTime_GetNanoseconds(measure);
+ assertTrue(nanos >= 1000000000ULL, "Expected more than 1,000,000 ns to have elapsed.");
+
+ longBowMeasureTime_Destroy(&measure);
+}
+
+LONGBOW_TEST_CASE(Global, longBowMeasureTime_Destroy)
+{
+ LongBowMeasureTime *measure = longBowMeasureTime_Start(1);
+ assertNotNull(measure, "Expected longBowMeasureTime_Start to return non-NULL result.");
+
+ longBowMeasureTime_Destroy(&measure);
+ assertNull(measure, "Expected longBowMeasureTime_Destroy to NULL the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, longBowMeasureTime)
+{
+ longBowMeasureTime(1)
+ {
+ sleep(2);
+ }
+}
+
+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[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_MeasureTime);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_Memory.c b/longbow/src/LongBow/test/test_longBow_Memory.c
new file mode 100755
index 00000000..d1943860
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_Memory.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.
+ */
+
+/**
+ */
+#include "../private/longBow_Memory.c"
+
+#include <LongBow/unit-test.h>
+#include <LongBow/debugging.h>
+
+LONGBOW_TEST_RUNNER(test_longBow_Memory)
+{
+ // 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_longBow_Memory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_longBow_Memory)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, longBowMemory_Allocate);
+ LONGBOW_RUN_TEST_CASE(Global, longBowMemory_Reallocate);
+ LONGBOW_RUN_TEST_CASE(Global, longBowMemory_StringCopy);
+}
+
+static uint64_t _setupAllocations;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ _setupAllocations = longBowMemory_OutstandingAllocations();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (longBowMemory_OutstandingAllocations() != _setupAllocations) {
+ printf("%s Memory leak\n", longBowTestCase_GetFullName(testCase));
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, longBowMemory_Allocate)
+{
+ void *memory = longBowMemory_Allocate(10);
+ assertNotNull(memory, "Return value from longBowMemory_Allocate(10) cannot be NULL.");
+ longBowMemory_Deallocate((void **) &memory);
+ assertNull(memory, "longBowMemory_Deallocated must NULL the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, longBowMemory_Reallocate)
+{
+ void *memory = longBowMemory_Allocate(10);
+ assertNotNull(memory, "Return value from longBowMemory_Allocate(10) cannot be NULL.");
+
+ memory = longBowMemory_Reallocate(memory, 100);
+ assertNotNull(memory, "Return value from longBowMemory_Reallocate cannot be NULL.");
+
+ longBowMemory_Deallocate((void **) &memory);
+ assertNull(memory, "longBowMemory_Deallocated must NULL the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, longBowMemory_Reallocate_NULL)
+{
+ void *memory = longBowMemory_Reallocate(NULL, 100);
+ assertNotNull(memory, "Return value from longBowMemory_Reallocate cannot be NULL.");
+
+ longBowMemory_Deallocate((void **) &memory);
+ assertNull(memory, "longBowMemory_Deallocated must NULL the pointer.");
+}
+
+LONGBOW_TEST_CASE(Global, longBowMemory_StringCopy)
+{
+ char *expected = "Hello World";
+
+ char *actual = longBowMemory_StringCopy(expected);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+ longBowMemory_Deallocate((void **) &actual);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_longBow_Memory);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_OpenFile.c b/longbow/src/LongBow/test/test_longBow_OpenFile.c
new file mode 100755
index 00000000..2a881fdb
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_OpenFile.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 <LongBow/testing.h>
+#include "../private/longBow_ArrayList.h"
+#include "../private/longBow_OpenFile.h"
+
+LONGBOW_TEST_RUNNER(longBow_Files)
+{
+ // 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(longBow_Files)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Files)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, longBow_OpenFiles);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, longBow_OpenFiles)
+{
+ LongBowArrayList *list = longBowOpenFile_CurrentlyOpen();
+ assertTrue(longBowArrayList_Length(list) > 0, "Expected the number of open files to be > 0");
+
+ longBowArrayList_Destroy(&list);
+}
+
+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[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Files);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_Properties.c b/longbow/src/LongBow/test/test_longBow_Properties.c
new file mode 100755
index 00000000..736a8141
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_Properties.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 the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <LongBow/longBow_Properties.h>
+#include "../private/longBow_Memory.h"
+
+LONGBOW_TEST_RUNNER(test_longBow_Properties)
+{
+ // 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_longBow_Properties)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_longBow_Properties)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, CreateDestroy);
+ LONGBOW_RUN_TEST_CASE(Global, longBowProperties_Set);
+ LONGBOW_RUN_TEST_CASE(Global, longBowProperties_Get);
+ LONGBOW_RUN_TEST_CASE(Global, longBowProperties_Length);
+ LONGBOW_RUN_TEST_CASE(Global, longBowProperties_Exists);
+}
+
+static uint64_t _setupAllocations;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ _setupAllocations = longBowMemory_OutstandingAllocations();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint64_t leaks = longBowMemory_OutstandingAllocations() - _setupAllocations;
+ if (leaks != 0) {
+ printf("%s leaks %" PRId64 " allocations.\n", longBowTestCase_GetFullName(testCase), leaks);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, CreateDestroy)
+{
+ LongBowProperties *properties = longBowProperties_Create();
+ longBowProperties_Destroy(&properties);
+}
+
+LONGBOW_TEST_CASE(Global, longBowProperties_Set)
+{
+ LongBowProperties *properties = longBowProperties_Create();
+ longBowProperties_Set(properties, "name", "value");
+ longBowProperties_Destroy(&properties);
+}
+
+LONGBOW_TEST_CASE(Global, longBowProperties_Get)
+{
+ LongBowProperties *properties = longBowProperties_Create();
+ char *expected = "value";
+ longBowProperties_Set(properties, "name", expected);
+
+ const char *actual = longBowProperties_Get(properties, "name");
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+ longBowProperties_Destroy(&properties);
+}
+
+LONGBOW_TEST_CASE(Global, longBowProperties_Length)
+{
+ LongBowProperties *properties = longBowProperties_Create();
+ assertTrue(longBowProperties_Length(properties) == 0, "Expected empty longBowProperties to be 0 length");
+
+ char *expected = "value";
+ longBowProperties_Set(properties, "name", expected);
+ assertTrue(longBowProperties_Length(properties) == 1, "Expected longBowProperties to be 1 length");
+
+ const char *actual = longBowProperties_Get(properties, "name");
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+ longBowProperties_Destroy(&properties);
+}
+
+LONGBOW_TEST_CASE(Global, longBowProperties_Exists)
+{
+ char *expected = "value";
+
+ LongBowProperties *properties = longBowProperties_Create();
+ assertFalse(longBowProperties_Exists(properties, expected), "Expected longBowProperties_Exists to be false");
+
+ longBowProperties_Set(properties, "name", expected);
+ assertTrue(longBowProperties_Exists(properties, "name"), "Expected longBowProperties_Exists to be true");
+
+ longBowProperties_Destroy(&properties);
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_longBow_Properties);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_Runner.c b/longbow/src/LongBow/test/test_longBow_Runner.c
new file mode 100755
index 00000000..7d7492e9
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_Runner.c
@@ -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.
+ */
+
+#include <LongBow/testing.h>
+
+LONGBOW_TEST_RUNNER(longBow_Runner)
+{
+ // 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(longBow_Runner)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Runner)
+{
+ 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[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Runner);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_Runtime.c b/longbow/src/LongBow/test/test_longBow_Runtime.c
new file mode 100755
index 00000000..b9d963e9
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_Runtime.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 <LongBow/testing.h>
+
+LONGBOW_TEST_RUNNER(longBow_Runtime)
+{
+ // 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(longBow_Runtime)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Runtime)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, longBowRuntime_StackTrace);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, longBowRuntime_StackTrace)
+{
+ longBowRuntime_StackTrace(1);
+}
+
+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[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Runtime);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_Status.c b/longbow/src/LongBow/test/test_longBow_Status.c
new file mode 100755
index 00000000..a1c01eb2
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_Status.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 <LongBow/testing.h>
+
+LONGBOW_TEST_RUNNER(longBow_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(longBow_Status)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Status)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, longBowStatus_ToString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, longBowStatus_ToString)
+{
+ char *expected;
+ char *actual;
+
+ expected = "Succeeded";
+ actual = longBowStatus_ToString(LONGBOW_STATUS_SUCCEEDED);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+ free(actual);
+
+ expected = "Warning";
+ actual = longBowStatus_ToString(LongBowStatus_WARNED);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+ free(actual);
+
+ expected = "Tear Down Warning";
+ actual = longBowStatus_ToString(LongBowStatus_TEARDOWN_WARNED);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+ free(actual);
+
+ expected = "Skipped";
+ actual = longBowStatus_ToString(LONGBOW_STATUS_SKIPPED);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+ free(actual);
+
+ expected = "Unimplemented";
+ actual = longBowStatus_ToString(LongBowStatus_UNIMPLEMENTED);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+ free(actual);
+
+ expected = "Impotent";
+ actual = longBowStatus_ToString(LongBowStatus_IMPOTENT);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+ free(actual);
+
+ expected = "Failed";
+ actual = longBowStatus_ToString(LONGBOW_STATUS_FAILED);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+ free(actual);
+
+ expected = "Stopped";
+ actual = longBowStatus_ToString(LongBowStatus_STOPPED);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+ free(actual);
+
+ expected = "Tear Down Failed";
+ actual = longBowStatus_ToString(LONGBOW_STATUS_TEARDOWN_FAILED);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+ free(actual);
+
+ expected = "Setup Failed";
+ actual = longBowStatus_ToString(LONGBOW_STATUS_SETUP_FAILED);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+ free(actual);
+
+ expected = "Memory Leak";
+ actual = longBowStatus_ToString(LONGBOW_STATUS_MEMORYLEAK);
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+ free(actual);
+
+ actual = longBowStatus_ToString(LongBowStatus_SIGNALLED + 1);
+ assertNotNull(actual, "Expected longBowStatus_ToString to return non-null value");
+ free(actual);
+}
+
+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[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Status);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_String.c b/longbow/src/LongBow/test/test_longBow_String.c
new file mode 100755
index 00000000..96750706
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_String.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <stdio.h>
+#include <inttypes.h>
+
+#include "../private/longBow_String.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(longBow_String)
+{
+ // 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(longBow_String)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(longBow_String)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, longBowString_Create);
+ LONGBOW_RUN_TEST_CASE(Global, longBowString_Append);
+ LONGBOW_RUN_TEST_CASE(Global, longBowString_Append_Append);
+ LONGBOW_RUN_TEST_CASE(Global, longBowString_Format);
+
+ LONGBOW_RUN_TEST_CASE(Global, longBowString_StartsWith_True);
+ LONGBOW_RUN_TEST_CASE(Global, longBowString_StartsWith_False);
+ LONGBOW_RUN_TEST_CASE(Global, longBowString_Tokenise);
+ LONGBOW_RUN_TEST_CASE(Global, longBowString_Tokenise_empty);
+ LONGBOW_RUN_TEST_CASE(Global, longBowString_Tokenise_NULL);
+ LONGBOW_RUN_TEST_CASE(Global, longBowString_CoreDump);
+}
+
+static uint64_t _outstandingAllocations;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ _outstandingAllocations = longBowMemory_OutstandingAllocations();
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (longBowMemory_OutstandingAllocations() > _outstandingAllocations) {
+ printf("%s: memory leak\n", longBowTestCase_GetName(testCase));
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, longBowString_Create)
+{
+ LongBowString *string = longBowString_Create(128);
+ assertNotNull(string, "Expected non-NULL result from longBowString_Create");
+
+ longBowString_Destroy(&string);
+ assertNull(string, "Expected the instance pointer to be NULL after longBowString_Destroy");
+}
+
+LONGBOW_TEST_CASE(Global, longBowString_Append)
+{
+ char *expected = "Hello World";
+ LongBowString *string = longBowString_Create(0);
+ longBowString_Append(string, expected);
+
+ assertTrue(strcmp(expected, string->buffer) == 0,
+ "Expected buffer to contain '%s', actual '%s'", expected, string->buffer);
+ longBowString_Destroy(&string);
+}
+
+LONGBOW_TEST_CASE(Global, longBowString_Append_Append)
+{
+ char *expected = "Hello World";
+ LongBowString *string = longBowString_Create(0);
+ longBowString_Append(string, "Hello");
+ longBowString_Append(string, " ");
+ longBowString_Append(string, "World");
+
+ assertTrue(strcmp(expected, string->buffer) == 0,
+ "Expected buffer to contain '%s', actual '%s'", expected, string->buffer);
+ longBowString_Destroy(&string);
+}
+
+LONGBOW_TEST_CASE(Global, longBowString_Format)
+{
+ char *expected = "Hello World";
+ LongBowString *string = longBowString_Create(0);
+ longBowString_Format(string, "%s", expected);
+
+ assertTrue(strcmp(expected, string->buffer) == 0,
+ "Expected buffer to contain '%s', actual '%s'", expected, string->buffer);
+ longBowString_Destroy(&string);
+}
+
+LONGBOW_TEST_CASE(Global, longBowString_StartsWith_True)
+{
+ bool actual = longBowString_StartsWith("abcde", "abc");
+ assertTrue(actual, "Expected true");
+}
+
+LONGBOW_TEST_CASE(Global, longBowString_StartsWith_False)
+{
+ bool actual = longBowString_StartsWith("abcde", "ayz");
+
+ assertFalse(actual, "Expected false");
+}
+
+LONGBOW_TEST_CASE(Global, longBowString_Tokenise)
+{
+ LongBowArrayList *actual = longBowString_Tokenise("--t.x=10", "-=");
+
+ assertTrue(strcmp("t.x", longBowArrayList_Get(actual, 0)) == 0,
+ "Expected first token to be t.x, actual %s", (char *) longBowArrayList_Get(actual, 0));
+ assertTrue(strcmp("10", longBowArrayList_Get(actual, 1)) == 0,
+ "Expected first token to be 10, actual %s", (char *) longBowArrayList_Get(actual, 1));
+
+ longBowArrayList_Destroy(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, longBowString_Tokenise_empty)
+{
+ LongBowArrayList *actual = longBowString_Tokenise("", "-=");
+
+ assertTrue(longBowArrayList_Length(actual) == 0, "Expected zero length LongBowArrayList, actual %zd", longBowArrayList_Length(actual));
+
+ longBowArrayList_Destroy(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, longBowString_Tokenise_NULL)
+{
+ LongBowArrayList *actual = longBowString_Tokenise(NULL, "-=");
+
+ assertTrue(longBowArrayList_Length(actual) == 0, "Expected zero length LongBowArrayList, actual %zd", longBowArrayList_Length(actual));
+
+ longBowArrayList_Destroy(&actual);
+}
+
+LONGBOW_TEST_CASE(Global, longBowString_CoreDump)
+{
+ //assertFalse(true, "foo");
+}
+
+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[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_String);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_TestCase.c b/longbow/src/LongBow/test/test_longBow_TestCase.c
new file mode 100755
index 00000000..3fe6c8e1
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_TestCase.c
@@ -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.
+ */
+
+#include <LongBow/testing.h>
+
+LONGBOW_TEST_RUNNER(longBow_TestCase)
+{
+ // 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(longBow_TestCase)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(longBow_TestCase)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, ExpectEvent);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, ExpectEvent)
+{
+}
+
+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[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_TestCase);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_TestCaseClipBoard.c b/longbow/src/LongBow/test/test_longBow_TestCaseClipBoard.c
new file mode 100755
index 00000000..521a817b
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_TestCaseClipBoard.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 <inttypes.h>
+#include <LongBow/testing.h>
+#include <LongBow/private/longBow_Memory.h>
+
+LONGBOW_TEST_RUNNER(longBow_TestCaseClipBoard)
+{
+ // 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(longBow_TestCaseClipBoard)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(longBow_TestCaseClipBoard)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, longBowTestCaseClipBoard_CreateDestroy);
+ LONGBOW_RUN_TEST_CASE(Global, longBowTestCaseClipBoard_Get);
+ LONGBOW_RUN_TEST_CASE(Global, longBowTestCaseClipBoard_Set);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, longBowTestCaseClipBoard_CreateDestroy)
+{
+ uint64_t allocations = longBowMemory_OutstandingAllocations();
+ char *shared = longBowMemory_StringCopy("shared data");
+
+ LongBowTestCaseClipBoard *clipboard = longBowTestCaseClipBoard_Create(shared);
+ assertNotNull(clipboard, "Expected non-null result from longBowTestCaseClipBoard_Create");
+
+ longBowTestCaseClipBoard_Destroy(&clipboard);
+ longBowMemory_Deallocate((void **) &shared);
+
+ assertTrue(longBowMemory_OutstandingAllocations() == allocations,
+ "Memory leaks %" PRId64, longBowMemory_OutstandingAllocations());
+}
+
+LONGBOW_TEST_CASE(Global, longBowTestCaseClipBoard_Get)
+{
+ char *shared = longBowMemory_StringCopy("shared data");
+
+ LongBowTestCaseClipBoard *clipboard = longBowTestCaseClipBoard_Create(shared);
+
+ char *actual = longBowTestCaseClipBoard_Get(clipboard);
+ assertTrue(strcmp(shared, actual) == 0, "Expected %s, actual %s", shared, actual);
+
+ longBowTestCaseClipBoard_Destroy(&clipboard);
+ longBowMemory_Deallocate((void **) &shared);
+}
+
+LONGBOW_TEST_CASE(Global, longBowTestCaseClipBoard_Set)
+{
+ char *shared = longBowMemory_StringCopy("shared data");
+
+ LongBowTestCaseClipBoard *clipboard = longBowTestCaseClipBoard_Create(shared);
+
+ char *expected = longBowMemory_StringCopy("expected");
+
+ longBowTestCaseClipBoard_Set(clipboard, expected);
+ char *actual = longBowTestCaseClipBoard_Get(clipboard);
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+
+ longBowTestCaseClipBoard_Destroy(&clipboard);
+ longBowMemory_Deallocate((void **) &shared);
+ longBowMemory_Deallocate((void **) &expected);
+}
+
+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[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_TestCaseClipBoard);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/test/test_longBow_UnitTesting.c b/longbow/src/LongBow/test/test_longBow_UnitTesting.c
new file mode 100755
index 00000000..de0f9c56
--- /dev/null
+++ b/longbow/src/LongBow/test/test_longBow_UnitTesting.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 "../testing.h"
+
+LONGBOW_TEST_RUNNER(longBow_UnitTesting)
+{
+ // 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(longBow_UnitTesting)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(longBow_UnitTesting)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, longBowUnitTesting_AssertCompareToContract);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+static int
+compareTo(const void *a, const void *b)
+{
+ if (a == NULL) {
+ if (b == NULL) {
+ return 0;
+ }
+ return -1;
+ } else {
+ if (b == NULL) {
+ return 1;
+ }
+ }
+
+ return strcmp(a, b);
+}
+
+LONGBOW_TEST_CASE(Global, longBowUnitTesting_AssertCompareToContract)
+{
+ char *exemplar = "exemplar";
+ void *equivalent[] = {
+ "exemplar",
+ NULL,
+ };
+ void *lesser[] = {
+ "exempla",
+ NULL,
+ };
+ void *greater[] = {
+ "exemplarr",
+ "fexemplarr",
+ NULL,
+ };
+
+ bool expected = true;
+ bool actual = longBowUnitTesting_AssertCompareToContract(compareTo, exemplar, equivalent, lesser, greater);
+
+ assertTrue(expected == actual, "Expected %d, actual %d", expected, actual);
+}
+
+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[])
+{
+ LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_UnitTesting);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/LongBow/testing.h b/longbow/src/LongBow/testing.h
new file mode 100755
index 00000000..d789094c
--- /dev/null
+++ b/longbow/src/LongBow/testing.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 testing.h
+ * @ingroup testing
+ * @brief LongBow testing functionality.
+ *
+ */
+#ifndef LongBow_testing_h
+#define LongBow_testing_h
+
+#include <LongBow/longBow_Compiler.h>
+#include <LongBow/longBow_ClipBoard.h>
+#include <LongBow/longBow_Properties.h>
+#include <LongBow/unit-test.h>
+#endif // LongBow_testing_h
diff --git a/longbow/src/LongBow/tests.h b/longbow/src/LongBow/tests.h
new file mode 100644
index 00000000..24146d4c
--- /dev/null
+++ b/longbow/src/LongBow/tests.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 tests.h
+ * @brief LongBow Utility Tests
+ *
+ *
+ */
+#ifndef LongBow_tests_h
+#define LongBow_tests_h
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+/**
+ * Test if an address is aligned.
+ *
+ * Return true of the given address is aligned according to alignment.
+ * The value for alignment must be a power of 2.
+ *
+ * @param [in] address The adddress to test.
+ * @param [in] alignment A power of 2 greater than or equal to sizeof(void *).
+ *
+ * @return true if the address is aligned.
+ * @return false if the address is not aligned.
+ */
+bool longBowRuntime_TestAddressIsAligned(const void *address, size_t alignment);
+
+/**
+ * Induce a core-dump
+ *
+ */
+void longBowRuntime_CoreDump(void);
+#endif // LongBow_tests_h
diff --git a/longbow/src/LongBow/traps.h b/longbow/src/LongBow/traps.h
new file mode 100755
index 00000000..e6c68d65
--- /dev/null
+++ b/longbow/src/LongBow/traps.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 traps.h
+ * @ingroup runtime
+ * @brief Runtime and Test Traps
+ *
+ */
+#ifndef LongBow_traps_h
+#define LongBow_traps_h
+
+/**
+ * @def trapUnrecoverableState
+ * @brief Lay a trap to report an unrecoverable state in program execution.
+ *
+ * @param ... A printf(3) format string of explanitory text and values
+ */
+#define trapUnrecoverableState(...) \
+ longBowTrap(&LongBowTrapUnrecoverableState, "Unrecoverable State: " __VA_ARGS__)
+
+/**
+ * @def trapNotImplemented
+ * @brief Lay a trap to report and abort an unimplemented capability.
+ *
+ * @param ... A printf(3) format string of explanitory text and values
+ */
+#define trapNotImplemented(...) \
+ longBowTrap(&LongBowTrapNotImplemented, "Feature not implemented: " __VA_ARGS__)
+
+/**
+ * @def trapIllegalValue
+ * @brief Trap an illegal value.
+ *
+ * To used for capturing parameter validation, for example.
+ *
+ * @param [in] argumentName A name that is displayed in the report message.
+ * @param [in] ... A printf format string and associated parameters.
+ */
+#define trapIllegalValue(argumentName, ...) \
+ longBowTrap(&LongBowTrapIllegalValue, "Illegal value for '" #argumentName "': " __VA_ARGS__)
+
+/**
+ * @def trapIllegalValueIf
+ * @brief Trap an illegal value if a condition is met.
+ *
+ * To used for the case where the value is valid
+ * (eg. it is the correct type) but is an illegal value to be used in the context in which it was attempted to be applied.
+ *
+ * @param [in] condition A logical expression that if true, induces this trap.
+ * @param [in] ... A printf format string and associated parameters.
+ */
+#define trapIllegalValueIf(condition, ...) \
+ longBowTrapIf(&LongBowTrapIllegalValue, condition, "Illegal value: " __VA_ARGS__)
+
+/**
+ * @def trapInvalidValueIf
+ * @brief Trap an invalid value if a condition is met.
+ *
+ * Used for capturing parameter validation.
+ * For example, a composite value (C struct) has an internally invalid state for example.
+ *
+ * @param [in] condition A logical expression that if true, induces this trap.
+ * @param [in] ... A printf format string and associated parameters.
+ */
+#define trapInvalidValueIf(condition, ...) \
+ longBowTrapIf(&LongBowTrapInvalidValue, condition, "Invalid value: " __VA_ARGS__)
+
+/**
+ * @def trapOutOfBounds
+ * @brief Trap an out-of-bounds condition on an index.
+ *
+ * @param [in] index The index that is out of bounds.
+ * @param [in] ... A printf format string and associated parameters.
+ */
+#define trapOutOfBounds(index, ...) \
+ longBowTrap(&LongBowTrapOutOfBounds, "Element out of bounds, " #index ": " __VA_ARGS__)
+
+/**
+ * @def trapOutOfBoundsIf
+ * @brief Trap an out-of-bounds condition for a specific value.
+ *
+ * @param [in] condition A logical expression that if true, induces this trap.
+ * @param [in] ... A printf format string and associated parameters.
+ */
+#define trapOutOfBoundsIf(condition, ...) \
+ longBowTrapIf(&LongBowTrapOutOfBounds, condition, "Out of bounds: " __VA_ARGS__)
+
+/**
+ * @def trapOutOfMemory
+ * @brief Signal that no more memory could be allocated.
+ *
+ * @param ... A printf format string and accompanying parameters.
+ */
+#define trapOutOfMemory(...) \
+ longBowTrap(&LongBowTrapOutOfMemoryEvent, "Out of memory. " __VA_ARGS__)
+
+/**
+ * @def trapOutOfMemoryIf
+ * @brief Signal that no more memory could be allocated.
+ *
+ * @param [in] condition A logical expression that if true, induces this trap.
+ * @param [in] ... A printf format string and associated parameters.
+ */
+#define trapOutOfMemoryIf(condition, ...) \
+ longBowTrapIf(&LongBowTrapOutOfMemoryEvent, condition, "Out of memory. " __VA_ARGS__)
+
+/**
+ * @def trapUnexpectedState
+ * @brief Signal that an unexpected or inconsistent state was encountered.
+ *
+ * @param ... A printf format string and accompanying parameters.
+ */
+#define trapUnexpectedState(...) \
+ longBowTrap(&LongBowTrapUnexpectedStateEvent, "Unexpected state. " __VA_ARGS__)
+
+/**
+ * @def trapUnexpectedStateIf
+ * @brief If the given condition is true, signal that an unexpected state was encountered .
+ *
+ * @param [in] condition A logical expression that if true, induces this trap.
+ * @param [in] ... A printf format string and associated parameters.
+ */
+#define trapUnexpectedStateIf(condition, ...) \
+ longBowTrapIf(&LongBowTrapUnexpectedStateEvent, condition, "Unexpected state: " __VA_ARGS__)
+
+/**
+ * @def trapCoreDump
+ * @brief Send a SIGTRAP to the current process.
+ */
+#define trapCoreDump() \
+ kill(0, SIGTRAP);
+
+/**
+ * @def trapCannotObtainLock
+ * @brief Signal that a lock could not be obtained.
+ *
+ * @param ... A printf format string and accompanying parameters.
+ */
+#define trapCannotObtainLock(...) \
+ longBowTrap(&LongBowTrapCannotObtainLockEvent, "Cannot obtain lock " __VA_ARGS__)
+
+/**
+ * @def trapCannotObtainLock
+ * @brief Signal that a lock could not be obtained.
+ *
+ * @param ... A printf format string and accompanying parameters.
+ */
+#define trapCannotObtainLockIf(condition, ...) \
+ longBowTrapIf(&LongBowTrapCannotObtainLockEvent, condition, "Cannot obtain lock " __VA_ARGS__)
+
+#endif
diff --git a/longbow/src/LongBow/unit-test.h b/longbow/src/LongBow/unit-test.h
new file mode 100644
index 00000000..3f282671
--- /dev/null
+++ b/longbow/src/LongBow/unit-test.h
@@ -0,0 +1,413 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 unit-test.h
+ * @ingroup testing
+ * @brief LongBow Unit Test Support.
+ *
+ * Every LongBow Test module must include this file as the first included file <em>after</em>
+ * including the files necessary for the functions under test.
+ *
+ */
+#ifndef UNIT_TEST_H_
+#define UNIT_TEST_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <unistd.h>
+
+#include <LongBow/runtime.h>
+
+#include <LongBow/longBow_Compiler.h>
+#include <LongBow/longBow_UnitTest.h>
+#include <LongBow/longBow_Status.h>
+#include <LongBow/longBow_Config.h>
+#include <LongBow/longBow_UnitTesting.h>
+#include <LongBow/longBow_Runtime.h>
+#include <LongBow/longBow_Main.h>
+#include <LongBow/longBow_TestRunner.h>
+#include <LongBow/longBow_TestFixture.h>
+#include <LongBow/longBow_TestCase.h>
+#include <LongBow/longBow_SubProcess.h>
+#include <LongBow/longBow_TestCaseMetaData.h>
+#include <LongBow/Reporting/longBowReport_Testing.h>
+
+#define longBowUnused(declaration) declaration __attribute__((unused))
+
+/**
+ * Test Runner setup function called before the invocation of the Test Fixtures associated with this Test Runner.
+ *
+ * Every Test Runner has a set-up and tear-down function that are invoked
+ * just before and just after the execution of each test case function.
+ * This function performs setup common for all fixtures to use.
+ * If this function must return a valid `LongBowStatus` value.
+ *
+ * @param [in] runnerName A valid identifier for the Test Runner.
+ *
+ * @return A LongBowStatus indicating the status of the setup.
+ *
+ * Example:
+ * @code
+ * // An example of a minimal Test Runner Setup function.
+ *
+ * LONGBOW_TEST_RUNNER_SETUP(LongBow)
+ * {
+ * return LONGBOW_STATUS_SUCCEEDED;
+ * }
+ * @endcode
+ *
+ * @see LONGBOW_TEST_RUNNER_TEARDOWN
+ */
+#define LONGBOW_TEST_RUNNER_SETUP(runnerName) \
+ LongBowStatus longBowUnitTest_RunnerSetupName(runnerName) (LongBowTestRunner * testRunner); \
+ LongBowStatus longBowUnitTest_RunnerSetupName(runnerName) (longBowUnused(LongBowTestRunner * testRunner))
+
+/**
+ * @brief The post-processing for a Test Runner called after all fixtures have been run.
+ *
+ * The Test Runner calls this function once after all the Test Fixtures are run.
+ *
+ * This function is responsible for resetting or restoring external resources previously setup by the
+ * Test Runner Setup function and which may have been modified by any test fixture or test case.
+ * If this function must return a valid LongBowStatus value.
+ *
+ * @see LONGBOW_TEST_RUNNER_SETUP
+ * @param [in] longBowRunnerName A valid identifier for the Test Runner.
+ */
+#define LONGBOW_TEST_RUNNER_TEARDOWN(longBowRunnerName) \
+ LongBowStatus longBowUnitTest_RunnerTearDownName(longBowRunnerName) (LongBowTestRunner * testRunner); \
+ LongBowStatus longBowUnitTest_RunnerTearDownName(longBowRunnerName) (longBowUnused(LongBowTestRunner * testRunner))
+
+/**
+ * @brief Define a Test Case Runner with the given name.
+ * The name must be valid syntax for a C identifier and will be used to compose a longer C function name.
+ *
+ * The resulting function that this macro defines specifies the parameter `LongBowTestRunner *testRunner`
+ * which is a pointer to a LongBowTestRunner instance for the Test Runner.
+ *
+ * @param [in] testRunnerName A valid identifier for the Test Runner.
+ */
+#define LONGBOW_TEST_RUNNER(testRunnerName) \
+ void longBowUnitTest_RunnerName(testRunnerName) (const LongBowTestRunner * testRunner); \
+ void longBowUnitTest_RunnerName(testRunnerName) (const LongBowTestRunner * testRunner)
+
+/**
+ * @brief Create an allocated instance of a LongBowTestRunner that must be destroyed via `longBowTestRunner_Destroy`
+ *
+ * @param [in] testRunnerName A valid identifier for the Test Runner. (see LONGBOW_TEST_RUNNER)
+ * @return The return value from longBowTestRunner_Create
+ */
+#define LONGBOW_TEST_RUNNER_CREATE(testRunnerName) \
+ longBowTestRunner_Create(#testRunnerName, \
+ longBowUnitTest_RunnerSetupName(testRunnerName), \
+ (LongBowTestRunnerRun *) longBowUnitTest_RunnerName(testRunnerName), \
+ longBowUnitTest_RunnerTearDownName(testRunnerName))
+
+#define LongBowTestRunner_Create(_runnerName_) \
+ longBowTestRunner_Create(#_runnerName_, longBowUnitTest_RunnerSetupName(_runnerName_), \
+ longBowUnitTest_RunnerName(_runnerName_), longBowUnitTest_RunnerTearDownName(_runnerName_))
+
+/**
+ * @brief Run the LongBow test fixture with the specified `fixtureName`.
+ *
+ * @param [in] LongBowTestFixtureName A valid C identifier
+ * @see LONGBOW_TEST_FIXTURE(fixtureName)
+ */
+#define LONGBOW_RUN_TEST_FIXTURE(LongBowTestFixtureName) \
+ do { \
+ extern LONGBOW_TEST_FIXTURE_SETUP(LongBowTestFixtureName); \
+ extern LONGBOW_TEST_FIXTURE_TEARDOWN(LongBowTestFixtureName); \
+ extern LongBowUnitTest_FixtureDeclaration(LongBowTestFixtureName); \
+ extern LongBowTestFixtureConfig longBowUnitTest_FixtureConfigName(LongBowTestFixtureName); \
+ longBowTestFixture_Run(testRunner, \
+ #LongBowTestFixtureName, \
+ &longBowUnitTest_FixtureConfigName(LongBowTestFixtureName), \
+ longBowUnitTest_FixtureSetupName(LongBowTestFixtureName), \
+ longBowUnitTest_FixtureName(LongBowTestFixtureName), \
+ longBowUnitTest_FixtureTearDownName(LongBowTestFixtureName)); \
+ } while (0)
+
+
+
+/**
+ * @brief Define a test fixture with the given `fixtureName`.
+ *
+ * The value for `fixtureName` must be a valid syntax for a C identifier.
+ *
+ * @param [in] fixtureName A valid syntax for a C identifier.
+ */
+#define LongBowUnitTest_FixtureDeclaration(_fixtureName_) \
+ void longBowUnitTest_FixtureName(_fixtureName_)(longBowUnused(const LongBowTestRunner * testRunner), longBowUnused(const LongBowTestFixture * testFixture))
+
+/**
+ * @brief The default value for the expected result of a LongBow Fixture.
+ */
+#define LONGBOW_TEST_FIXTURE_CONFIG_DEFAULT .enabled = true
+
+/**
+ * @brief Define a test fixture with the given `fixtureName`.
+ *
+ * The value for `fixtureName` must be valid syntax for a C identifier.
+ *
+ * The resulting function that this macro defines specifies the parameter `LongBowTestFixture *LongBowTestFixture`
+ * which is a pointer to a `LongBowTestFixture` instance for the Test Fixture.
+ *
+ * @param [in] fixtureName
+ */
+#define LONGBOW_TEST_FIXTURE(fixtureName) \
+ LONGBOW_TEST_FIXTURE_OPTIONS(fixtureName, LONGBOW_TEST_FIXTURE_CONFIG_DEFAULT)
+
+#define LONGBOW_TEST_FIXTURE_OPTIONS(fixtureName, ...) \
+ LongBowCompiler_IgnoreInitializerOverrides \
+ LongBowTestFixtureConfig longBowUnitTest_FixtureConfigName(fixtureName) = { LONGBOW_TEST_FIXTURE_CONFIG_DEFAULT, __VA_ARGS__ }; \
+ LongBowCompiler_WarnInitializerOverrides \
+ extern LONGBOW_TEST_FIXTURE_SETUP(fixtureName); \
+ extern LONGBOW_TEST_FIXTURE_TEARDOWN(fixtureName); \
+ LongBowUnitTest_FixtureDeclaration(fixtureName); \
+ LongBowUnitTest_FixtureDeclaration(fixtureName)
+
+
+/**
+ * The pre-processing for a test fixture called before each invocation of a test case in the same fixture.
+ *
+ * This function is responsible for setting up the common programmatic state for each test case in the same fixture.
+ * If this function returns `false` the corresponding test case is skipped.
+ *
+ * The resulting function that this macro defines specifies the parameters
+ * `LongBowTestFixture *testFixture` and `LongBowTestCase *testCase`
+ *
+ * @param [in] fixtureName
+ *
+ * @see LONGBOW_TEST_FIXTURE_TEARDOWN
+ */
+#define LONGBOW_TEST_FIXTURE_SETUP(fixtureName) \
+ LongBowStatus longBowUnitTest_FixtureSetupName(fixtureName) (longBowUnused(const LongBowTestRunner * testRunner), longBowUnused(const LongBowTestFixture * testFixture), longBowUnused(const LongBowTestCase * testCase), longBowUnused(LongBowClipBoard * testClipBoard))
+
+/**
+ * The post-processing for a test fixture called after each invocation of a test case in the same fixture.
+ *
+ * This function is responsible for resetting the common programmatic state for each test case in the same fixture.
+ * If this function returns `false` the corresponding test case is considered passed, but warned.
+ *
+ * The resulting function that this macro defines specifies the parameters
+ * `LongBowTestFixture *testFixture` and `LongBowTestCase *testCase`
+ *
+ * @param [in] fixtureName
+ *
+ * @see `LONGBOW_TEST_FIXTURE_SETUP`
+ */
+#define LONGBOW_TEST_FIXTURE_TEARDOWN(fixtureName) \
+ LongBowStatus longBowUnitTest_FixtureTearDownName(fixtureName) (longBowUnused(const LongBowTestRunner * testRunner), longBowUnused(const LongBowTestFixture * testFixture), longBowUnused(const LongBowTestCase * testCase), longBowUnused(LongBowClipBoard * testClipBoard))
+
+/**
+ * @brief Defines the canonical name of a LongBow Test Case meta data.
+ *
+ * @param fixtureName The name of the Test Fixture that the Test Case belongs to.
+ * @param testCaseName The name of the Test Case.
+ */
+#define longBowTestCase_MetaDataDeclaration(_testFixtureName_, _testCaseName_) \
+ TestCase ## _testFixtureName_ ## _testCaseName_ ## MetaData
+
+/**
+ * @brief Forward declare a LongBow Test Case.
+ *
+ * @param fixtureName The name of the Test Fixture that the Test Case belongs to.
+ * @param testCaseName The name of the Test Case.
+ */
+#define longBowUnitTest_TestCaseDeclaration(fixtureName, testCaseName) \
+ void longBowUnitTest_CaseName(fixtureName, testCaseName) (longBowUnused(const LongBowTestRunner * testRunner), longBowUnused(const LongBowTestFixture * testFixture), longBowUnused(const LongBowTestCase * testCase), longBowUnused(const LongBowClipBoard * testClipBoard), longBowUnused(jmp_buf longBowTestCaseAbort))
+
+/**
+ * @brief The default value for the expected result of a LongBow Test Case.
+ */
+#define LongBowUnitTest_TestCaseDefaultExpectedResult .event = NULL, .status = LongBowStatus_DONTCARE
+
+/**
+ * Define a test case with the given `fixtureName` and `testCaseName`.
+ *
+ * The `fixtureName` must be the name of a defined fixture, see `LONGBOW_TEST_FIXTURE`.
+ * The `testCaseName` must be valid syntax for a C identifier.
+ *
+ * @param fixtureName
+ * @param testCaseName
+ *
+ * @code
+ * LONGBOW_TEST_CASE(MyFixture, MyTestCase)
+ * {
+ * assertTrue(true, "It lied to me!");
+ * }
+ */
+#define LONGBOW_TEST_CASE(fixtureName, testCaseName) \
+ LONGBOW_TEST_CASE_EXPECTS(fixtureName, testCaseName, LongBowUnitTest_TestCaseDefaultExpectedResult)
+
+/**
+ * Define a test case with the given `fixtureName` and `testCaseName` with an explictly specified status.
+ *
+ * The `fixtureName` must be the name of a defined fixture, see `LONGBOW_TEST_FIXTURE`.
+ * The `testCaseName` is the name of the Test Case and must be valid syntax for a C identifier.
+ * The variable number of subsequent arguments are a comma separated list of structure initialisers for the
+ * LongBowRuntimeResult structure.
+ *
+ * For example, the construct
+ * @code
+ * LONGBOW_TEST_CASE_EXPECTS(MyFixture, alwaysWarn, .event = &LongBowAssertEvent)
+ * @endcode
+ * defines the Long Bow Test case `alwaysWarn` that is within the Test Fixture named `MyFixture`.
+ * The expected termination is expected to be a `LongBowAssertEvent`, which means an assertion was triggered.
+ *
+ * If the termination status of the test must is equal to the specified status,
+ * the test will be signaled as `LONGBOW_STATUS_SUCCESS, otherwise it will be LONGBOW_STATUS_FAILED.
+ *
+ * @param fixtureName
+ * @param testCaseName
+ */
+#define LONGBOW_TEST_CASE_EXPECTS(fixtureName, testCaseName, ...) \
+ LongBowCompiler_IgnoreInitializerOverrides \
+ LongBowTestCaseMetaData longBowTestCase_MetaDataDeclaration(fixtureName, testCaseName) = \
+ { .fileName = __FILE__, .functionName = #testCaseName, .lineNumber = __LINE__, \
+ .expectedResult = { LongBowUnitTest_TestCaseDefaultExpectedResult, __VA_ARGS__ } }; \
+ LongBowCompiler_WarnInitializerOverrides \
+ longBowUnitTest_TestCaseDeclaration(fixtureName, testCaseName); \
+ longBowUnitTest_TestCaseDeclaration(fixtureName, testCaseName)
+
+
+/**
+ * @brief Run a test case defined for the named <code>fixtureName</code> and <code>testCaseName</code>.
+ *
+ * This is executed within a LongBow test fixture function and references the function's
+ * <code>LongBowTestFixture</code> parameter.
+ *
+ * @param [in] fixtureName
+ * @param [in] testCaseName
+ *
+ * @see LONGBOW_TEST_CASE
+ */
+#define LONGBOW_RUN_TEST_CASE(fixtureName, testCaseName) \
+ extern longBowUnitTest_TestCaseDeclaration(fixtureName, testCaseName); \
+ extern LongBowTestCaseMetaData longBowTestCase_MetaDataDeclaration(fixtureName, testCaseName); \
+ longBowTestCase_Run(#testCaseName, testFixture, longBowUnitTest_CaseName(fixtureName, testCaseName), \
+ &longBowTestCase_MetaDataDeclaration(fixtureName, testCaseName))
+
+/**
+ * @brief Configure and run a set of LongBowTestRunner instances
+ *
+ * @param [in] argc The number of elements in the @p argv array.
+ * @param [in] argv An array of nul-terminated C-strings.
+ *
+ * Example Usage:
+ * @code
+ * int
+ * main(int argc, char *argv[argc])
+ * {
+ * LongBowTestRunner *testRunner1 = LONGBOW_TEST_RUNNER_CREATE(MyTestRunner);
+ * LongBowTestRunner *testRunner2 = LONGBOW_TEST_RUNNER_CREATE(MyOtherTestRunner);
+ *
+ * int exitStatus = longBowMain(argc, argv, testRunner, testRunner2);
+ *
+ * longBowTestRunner_Destroy(&testRunner1);
+ * longBowTestRunner_Destroy(&testRunner2);
+ * exit(exitStatus);
+ * }
+ * @endcode
+ */
+#ifdef LongBow_DISABLE_ASSERTIONS
+/* 77 is the exit status for a skipped test when run with automake generated Makefiles */
+# define longBowMain(argc, argv, ...) \
+ 77
+#else
+# define longBowMain(argc, argv, ...) \
+ longBowMain_Impl(argc, argv, __VA_ARGS__, NULL)
+#endif
+
+/**
+ * @brief Configure and run a set of `LongBowTestRunner` instances
+ *
+ * @param [in] argc The number of elements in the @p argv array.
+ * @param [in] argv An NULL terminated list of pointers to `LongBowTestRunner` instances.
+ *
+ * Example Usage:
+ * @code
+ * int
+ * main(int argc, char *argv[argc])
+ * {
+ * LongBowTestRunner *testRunner1 = LONGBOW_TEST_RUNNER_CREATE(MyTestRunner);
+ * LongBowTestRunner *testRunner2 = LONGBOW_TEST_RUNNER_CREATE(MyOtherTestRunner);
+ *
+ * int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, testRunner2);
+ *
+ * longBowTestRunner_Destroy(&testRunner1);
+ * longBowTestRunner_Destroy(&testRunner2);
+ * exit(exitStatus);
+ * }
+ * @endcode
+ */
+#define LONGBOW_TEST_MAIN(argc, argv, ...) \
+ longBowMain(argc, argv, __VA_ARGS__, NULL)
+
+/**
+ * @brief Skip this test case
+ *
+ * @param [in] ... A printf format string followed by a variable number of parameters corresponding to the format string.
+ */
+#define testSkip(...) do { \
+ longBowTest(&LongBowTestSkippedEvent, "Skipped " __VA_ARGS__); \
+} while (0)
+
+/**
+ * @brief Terminate the test indicating that the test is unimplemented.
+ *
+ * @param [in] ... A printf format string followed by a variable number of parameters corresponding to the format string.
+ */
+#define testUnimplemented(...) do { \
+ longBowTest(&LongBowTestUnimplementedEvent, "Unimplemented test " __VA_ARGS__); \
+} while (0)
+
+/**
+ * @brief Issue a warning and terminate with the `LONGBOW_TESTCASE_WARNED` code.
+ *
+ * @param [in] ... A printf format string followed by a variable number of parameters corresponding to the format string.
+ */
+#define testWarn(...) \
+ do { longBowTest(&LongBowTestEvent, "Warning " __VA_ARGS__); } while (0)
+
+/**
+ * @brief assert the Equals Contract for the given function.
+ *
+ * @param [in] function The function under test.
+ * @param [in] x The pivotal value which must not be NULL.
+ * @param [in] y A value that must be perfectly equal to x and z, but neither x nor z.
+ * @param [in] z A value that must be perfectly equal to x and y, but neither x nor y.
+ * @param [in] ... A variable number of values that are unequal to x.
+ */
+#define assertEqualsContract(function, x, y, z, ...) \
+ assertTrue(longBowUnitTesting_AssertEqualsContract((bool (*)(void *, void *))function, x, y, z, __VA_ARGS__, NULL), "Failed Equals Contract");
+
+/**
+ * @brief assert the Compare To Contract for the given function.
+ *
+ * @param [in] function The function under test.
+ * @param [in] value The pivotal value under test.
+ * @param [in] equality A NULL terminated array of values that are all equivalent to `value`.
+ * @param [in] lesser A NULL terminated array of values that are all less than `value`.
+ * @param [in] greater A NULL terminated array of values that are all greater than `value`.
+ * @return `true` if the evalutation is successful.
+ * @see assertCompareToContract()
+ */
+#define assertCompareToContract(function, value, equality, lesser, greater) \
+ assertTrue(longBowUnitTesting_AssertCompareToContract((int (*)(const void *, const void *))function, value, (void *) equality, (void *) lesser, (void *) greater), "Failed CompareTo Contract");
+#endif // UNIT_TEST_H_
diff --git a/longbow/src/examples/.gitignore b/longbow/src/examples/.gitignore
new file mode 100644
index 00000000..1b4775c8
--- /dev/null
+++ b/longbow/src/examples/.gitignore
@@ -0,0 +1,5 @@
+*.gcno
+*.gcda
+*.dSYM
+*.gcov
+testLongBow
diff --git a/longbow/src/examples/example1.c b/longbow/src/examples/example1.c
new file mode 100755
index 00000000..31bbadbf
--- /dev/null
+++ b/longbow/src/examples/example1.c
@@ -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.
+ */
+
+/*
+ * example1.c
+ *
+ */
+
+#include <unistd.h>
+#include <stdbool.h>
+#include <signal.h>
+
+int
+alwaysTrue()
+{
+ return true;
+}
+
+int
+alwaysFalse()
+{
+ return false;
+}
+
+int
+alwaysSignalled()
+{
+ kill(getpid(), SIGTERM);
+ return true;
+}
diff --git a/longbow/src/examples/minimal.c b/longbow/src/examples/minimal.c
new file mode 100755
index 00000000..47f7e7fe
--- /dev/null
+++ b/longbow/src/examples/minimal.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * minimal.c
+ *
+ */
+
+int
+alwaysSucceed()
+{
+ return 1;
+}
diff --git a/longbow/src/examples/pointer.c b/longbow/src/examples/pointer.c
new file mode 100755
index 00000000..0a0fef95
--- /dev/null
+++ b/longbow/src/examples/pointer.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/runtime.h>
+#include <unistd.h>
+#include <string.h>
+
+void
+function(char *pointer)
+{
+ assertNotNull(pointer, "The pointer cannot be NULL.");
+
+ write(1, pointer, strlen(pointer));
+}
+
+int
+main(int argc, char *argv[])
+{
+ function(0);
+}
diff --git a/longbow/src/examples/require.c b/longbow/src/examples/require.c
new file mode 100755
index 00000000..31055aa8
--- /dev/null
+++ b/longbow/src/examples/require.c
@@ -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.
+ */
+
+#include <stdio.h>
+#include "../runtime.h"
+
+# define longBowAssert(eventPointer, condition, ...) \
+ longBowRuntime_EventEvaluation(eventPointer); \
+ if (longBowIsFalse(condition) && \
+ (longBowRuntime_EventTrigger(eventPointer, longBowLocation_Create(__FILE__, longBow_function, __LINE__), #condition, __VA_ARGS__), true)) \
+ for (; true; abort())
+
+
+int
+main(int argc, char *argv[argc])
+{
+ int condition = 1;
+
+ longBowAssert(&LongBowAssertEvent, condition == 1, "Message %d", 2)
+ {
+ printf("Should not have Triggered\n");
+ };
+ longBowAssert(&LongBowAssertEvent, condition == 0, "Message %d", 2)
+ {
+ printf("Triggered\n");
+ };
+
+ longBowAssert(&LongBowAssertEvent, condition == 0, "Message %d", 2);
+}
diff --git a/longbow/src/examples/testAssertion.c b/longbow/src/examples/testAssertion.c
new file mode 100755
index 00000000..eb60db91
--- /dev/null
+++ b/longbow/src/examples/testAssertion.c
@@ -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.
+ */
+
+#include "../runtime.h"
+
+int
+main(int argc, char *argv[])
+{
+ assertTrue(0, "Force this assertion.");
+}
diff --git a/longbow/src/examples/testClipboard.c b/longbow/src/examples/testClipboard.c
new file mode 100755
index 00000000..1e6a5b94
--- /dev/null
+++ b/longbow/src/examples/testClipboard.c
@@ -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.
+ */
+
+/**
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+LONGBOW_TEST_RUNNER(testClipboard)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(testClipboard)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(testClipboard)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, testClipboard);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ char *testData = strdup("Hello World");
+ longBowTestCase_SetClipBoardData(testCase, testData, free);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, testClipboard)
+{
+ char *testData = longBowTestCase_GetClipBoardData(testCase);
+ printf("Shared state '%s'\n", testData);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(testClipboard);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/examples/testExample1.c b/longbow/src/examples/testExample1.c
new file mode 100755
index 00000000..d26294a1
--- /dev/null
+++ b/longbow/src/examples/testExample1.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "../unit-test.h"
+
+#include "example1.c"
+
+LONGBOW_TEST_RUNNER(example1)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(example1)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(example1)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, strlen);
+ LONGBOW_RUN_TEST_CASE(Global, alwaysFail);
+ LONGBOW_RUN_TEST_CASE(Global, alwaysSignalled);
+ LONGBOW_RUN_TEST_CASE(Global, alwaysSucceed);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, alwaysFail)
+{
+ assertTrue(alwaysFalse(), "This test must always fail.")
+ {
+ printf("And this is extra code that is executed when the assertion fails");
+ }
+}
+
+LONGBOW_TEST_CASE(Global, alwaysSignalled)
+{
+ kill(getpid(), SIGTERM);
+}
+
+LONGBOW_TEST_CASE(Global, alwaysSucceed)
+{
+ assertTrue(alwaysTrue(), "This test must always succeed.");
+}
+
+LONGBOW_TEST_CASE(Global, strlen)
+{
+ assertNotNull(NULL, "Parameter must be a non-null char pointer.");
+}
+
+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(example1);
+ exit(longBowMain(argc, argv, testRunner, NULL));
+}
diff --git a/longbow/src/examples/testLongBow.c b/longbow/src/examples/testLongBow.c
new file mode 100755
index 00000000..7c1fd949
--- /dev/null
+++ b/longbow/src/examples/testLongBow.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.
+ */
+
+/*
+ * test_LongBow.c
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/errno.h>
+
+#include "../unit-test.h"
+
+
+LONGBOW_TEST_RUNNER(LongBow)
+{
+ LONGBOW_RUN_TEST_FIXTURE(LongBowFixture);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(LongBow)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(LongBow)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(LongBowFixture)
+{
+ LONGBOW_RUN_TEST_CASE(LongBowFixture, alwaysSucceed);
+ LONGBOW_RUN_TEST_CASE(LongBowFixture, alwaysUnimplemented);
+ LONGBOW_RUN_TEST_CASE(LongBowFixture, alwaysImpotent);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(LongBowFixture)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(LongBowFixture)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(LongBowFixture, testErrno)
+{
+ errno = ENOENT;
+ assertTrue(0, "Errno test");
+}
+
+LONGBOW_TEST_CASE(LongBowFixture, alwaysSucceed)
+{
+ assertTrue(1, "alwaysSucceed");
+}
+
+LONGBOW_TEST_CASE(LongBowFixture, alwaysImpotent)
+{
+}
+
+LONGBOW_TEST_CASE_EXPECTS(LongBowFixture, testEvent, .event = &LongBowAssertEvent)
+{
+ assertTrue(0, "testEvent");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(LongBowFixture, alwaysFail, .status = LONGBOW_STATUS_FAILED, .event = &LongBowAssertEvent)
+{
+ assertTrue(0, "alwaysFail");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(LongBowFixture, alwaysSigTERM, .status = LONGBOW_STATUS_SIGNAL(SIGTERM))
+{
+ kill(getpid(), SIGTERM);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(LongBowFixture, alwaysSEGV, .event = &LongBowEventSIGSEGV)
+{
+ int *p = 0;
+ int i = *p;
+ printf("not used %d\n", i);
+}
+
+LONGBOW_TEST_CASE(LongBowFixture, alwaysUnimplemented)
+{
+ testUnimplemented("alwaysUnimplemented");
+}
+
+LONGBOW_TEST_CASE(LongBowFixture, alwaysWarn)
+{
+ testWarn("alwaysWarn");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(LongBowFixture, alwaysSkip, .event = &LongBowTestSkippedEvent)
+{
+ testSkip("alwaysSkip");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(LongBowFixture, alwaysTrap, .status = LONGBOW_STATUS_FAILED)
+{
+ trapNotImplemented("alwaysTrap");
+}
+
+LONGBOW_TEST_FIXTURE(TestTearDownWarning)
+{
+ LONGBOW_RUN_TEST_CASE(TestTearDownWarning, alwaysFail);
+ LONGBOW_RUN_TEST_CASE(TestTearDownWarning, alwaysSucceed);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(TestTearDownWarning)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(TestTearDownWarning)
+{
+ return LONGBOW_STATUS_TEARDOWN_WARNED;
+}
+
+LONGBOW_TEST_CASE(TestTearDownWarning, alwaysFail)
+{
+ assertTrue(0, "alwaysFail");
+}
+
+LONGBOW_TEST_CASE(TestTearDownWarning, alwaysSucceed)
+{
+ assertTrue(1, "alwaysSucceed");
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(LongBow);
+ int status = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+
+ exit(status);
+}
diff --git a/longbow/src/examples/testRunnerSkipped.c b/longbow/src/examples/testRunnerSkipped.c
new file mode 100755
index 00000000..f071678d
--- /dev/null
+++ b/longbow/src/examples/testRunnerSkipped.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 <stdio.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(Example1)
+{
+ LONGBOW_RUN_TEST_FIXTURE(FixtureA);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(Example1)
+{
+ return LONGBOW_STATUS_SETUP_SKIPTESTS;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(Example1)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(FixtureA)
+{
+ LONGBOW_RUN_TEST_CASE(FixtureA, alwaysSucceed);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(FixtureA)
+{
+ assertTrue(0, "This should have been skipped and never be called.");
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(FixtureA)
+{
+ assertTrue(0, "This should have been skipped and never be called.");
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(FixtureA, alwaysSucceed)
+{
+ assertTrue(0, "This should have been skipped and never be called.");
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(Example1);
+ int status = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+
+ exit(status);
+}
diff --git a/longbow/src/examples/testTearDown.c b/longbow/src/examples/testTearDown.c
new file mode 100755
index 00000000..183563d9
--- /dev/null
+++ b/longbow/src/examples/testTearDown.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.
+ */
+
+/**
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+LONGBOW_TEST_RUNNER(testTearDown)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Succeeded);
+ LONGBOW_RUN_TEST_FIXTURE(Warned);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(testTearDown)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(testTearDown)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Succeeded)
+{
+ LONGBOW_RUN_TEST_CASE(Succeeded, testTearDown);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Succeeded)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Succeeded)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Succeeded, testTearDown)
+{
+ assertTrue(true, "");
+}
+
+
+LONGBOW_TEST_FIXTURE(Warned)
+{
+ LONGBOW_RUN_TEST_CASE(Warned, alwaysWarn);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Warned)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Warned)
+{
+ return LONGBOW_STATUS_TEARDOWN_WARNED;
+}
+
+LONGBOW_TEST_CASE(Warned, alwaysWarn)
+{
+ assertTrue(true, "");
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(testTearDown);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/longbow/src/examples/testUnimplemented.c b/longbow/src/examples/testUnimplemented.c
new file mode 100755
index 00000000..3ccf18d1
--- /dev/null
+++ b/longbow/src/examples/testUnimplemented.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 "../unit-test.h"
+
+LONGBOW_TEST_RUNNER(Unimplemented)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Unimplemented);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(Unimplemented)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(Unimplemented)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Unimplemented)
+{
+ LONGBOW_RUN_TEST_CASE(Unimplemented, Unimplemented);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Unimplemented)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Unimplemented)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Unimplemented, Unimplemented)
+{
+ testUnimplemented("Unimplemented");
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(Unimplemented);
+ int status = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+
+ exit(status);
+}
diff --git a/longbow/src/examples/test_minimal.c b/longbow/src/examples/test_minimal.c
new file mode 100755
index 00000000..5089071c
--- /dev/null
+++ b/longbow/src/examples/test_minimal.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../unit-test.h"
+
+#include "minimal.c"
+
+LONGBOW_TEST_RUNNER(Example1)
+{
+ LONGBOW_RUN_TEST_FIXTURE(FixtureA);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(Example1)
+{
+ return true;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(Example1)
+{
+ return true;
+}
+
+LONGBOW_TEST_FIXTURE(FixtureA)
+{
+ LONGBOW_RUN_TEST_CASE(FixtureA, alwaysSucceed);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(FixtureA)
+{
+ return true;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(FixtureA)
+{
+ return true;
+}
+
+LONGBOW_TEST_CASE(FixtureA, alwaysSucceed)
+{
+ assertTrue(alwaysSucceed(), "This must always succeed.");
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(Example1);
+ int status = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+
+ exit(status);
+}
diff --git a/longbow/src/examples/tutorial/.gitignore b/longbow/src/examples/tutorial/.gitignore
new file mode 100644
index 00000000..fb63b40b
--- /dev/null
+++ b/longbow/src/examples/tutorial/.gitignore
@@ -0,0 +1,3 @@
+test_tutorial11
+test_tutorial12
+test_tutorial13
diff --git a/longbow/src/examples/tutorial/test_tutorial1.c b/longbow/src/examples/tutorial/test_tutorial1.c
new file mode 100644
index 00000000..311b5357
--- /dev/null
+++ b/longbow/src/examples/tutorial/test_tutorial1.c
@@ -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.
+ */
+
+* /
+
+#include "tutorial.c"
diff --git a/longbow/src/examples/tutorial/test_tutorial10.c b/longbow/src/examples/tutorial/test_tutorial10.c
new file mode 100644
index 00000000..2eb62dc4
--- /dev/null
+++ b/longbow/src/examples/tutorial/test_tutorial10.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 "tutorial.c"
+
+#include <LongBow/unit-test.h>
+
+
+LONGBOW_TEST_RUNNER(myTutorialTest)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, alwaysSucceed);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, alwaysSucceed)
+{
+ bool result = alwaysSucceed();
+
+ assertTrue(result, "This test must always succeed.");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(myTutorialTest);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+
+ longBowTestRunner_Destroy(&testRunner);
+ exit(status);
+}
diff --git a/longbow/src/examples/tutorial/test_tutorial11.c b/longbow/src/examples/tutorial/test_tutorial11.c
new file mode 100644
index 00000000..58d44ed4
--- /dev/null
+++ b/longbow/src/examples/tutorial/test_tutorial11.c
@@ -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.
+ */
+
+* /
+
+#include "tutorial.c"
+
+#include <LongBow/unit-test.h>
+
+
+LONGBOW_TEST_RUNNER(myTutorialTest)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, alwaysSucceed);
+ LONGBOW_RUN_TEST_CASE(Global, alwaysFail);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, alwaysSucceed)
+{
+ bool result = alwaysSucceed();
+
+ assertTrue(result, "This test must always succeed.");
+}
+
+LONGBOW_TEST_CASE(Global, alwaysFail)
+{
+ bool result = alwaysFail();
+
+ assertTrue(result, "This test will fail.");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(myTutorialTest);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+
+ longBowTestRunner_Destroy(&testRunner);
+ exit(status);
+}
diff --git a/longbow/src/examples/tutorial/test_tutorial12.c b/longbow/src/examples/tutorial/test_tutorial12.c
new file mode 100644
index 00000000..63a2dc52
--- /dev/null
+++ b/longbow/src/examples/tutorial/test_tutorial12.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 "tutorial.c"
+
+#include <LongBow/unit-test.h>
+
+
+LONGBOW_TEST_RUNNER(myTutorialTest)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, alwaysSucceed);
+ LONGBOW_RUN_TEST_CASE(Global, alwaysFail);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, alwaysSucceed)
+{
+ bool result = alwaysSucceed();
+
+ assertTrue(result, "This test must always succeed.");
+}
+
+LONGBOW_TEST_CASE(Global, alwaysFail)
+{
+ bool result = alwaysFail();
+
+ assertTrue(result, "This test will fail.");
+}
+
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, _privateFunction);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Static, _privateFunction)
+{
+ bool result = _privateFunction();
+
+ assertTrue(result, "This test must always succeed.");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(myTutorialTest);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+
+ longBowTestRunner_Destroy(&testRunner);
+ exit(status);
+}
diff --git a/longbow/src/examples/tutorial/test_tutorial13.c b/longbow/src/examples/tutorial/test_tutorial13.c
new file mode 100644
index 00000000..6d35c9b6
--- /dev/null
+++ b/longbow/src/examples/tutorial/test_tutorial13.c
@@ -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.
+ */
+
+* /
+
+#include "tutorial.c"
+
+#include <LongBow/unit-test.h>
+
+
+LONGBOW_TEST_RUNNER(myTutorialTest)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, alwaysSucceed);
+ LONGBOW_RUN_TEST_CASE(Global, alwaysFail);
+ LONGBOW_RUN_TEST_CASE(Global, blowUp);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, alwaysSucceed)
+{
+ bool result = alwaysSucceed();
+
+ assertTrue(result, "This test must always succeed.");
+}
+
+LONGBOW_TEST_CASE(Global, alwaysFail)
+{
+ bool result = alwaysFail();
+
+ assertTrue(result, "This test will fail.");
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, blowUp, .event = &LongBowEventSIGSEGV)
+{
+ blowUp();
+
+ assertTrue(false, "This will not be executed");
+}
+
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, _privateFunction);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Static, _privateFunction)
+{
+ bool result = _privateFunction();
+
+ assertTrue(result, "This test must always succeed.");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(myTutorialTest);
+ int status = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+
+ longBowTestRunner_Destroy(&testRunner);
+ exit(status);
+}
diff --git a/longbow/src/examples/tutorial/test_tutorial2.c b/longbow/src/examples/tutorial/test_tutorial2.c
new file mode 100644
index 00000000..68e1d39a
--- /dev/null
+++ b/longbow/src/examples/tutorial/test_tutorial2.c
@@ -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.
+ */
+
+* /
+
+#include "tutorial.c"
+
+#include <LongBow/unit-test.h>
diff --git a/longbow/src/examples/tutorial/test_tutorial3.c b/longbow/src/examples/tutorial/test_tutorial3.c
new file mode 100644
index 00000000..fb635846
--- /dev/null
+++ b/longbow/src/examples/tutorial/test_tutorial3.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+* /
+
+#include "tutorial.c"
+
+#include <LongBow/unit-test.h>
+
+
+LONGBOW_TEST_RUNNER(myTutorialTest)
+{
+}
diff --git a/longbow/src/examples/tutorial/test_tutorial4.c b/longbow/src/examples/tutorial/test_tutorial4.c
new file mode 100644
index 00000000..b8461fe4
--- /dev/null
+++ b/longbow/src/examples/tutorial/test_tutorial4.c
@@ -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.
+ */
+
+* /
+
+#include "tutorial.c"
+
+#include <LongBow/unit-test.h>
+
+
+LONGBOW_TEST_RUNNER(myTutorialTest)
+{
+}
+
+LONGBOW_TEST_RUNNER_SETUP(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
diff --git a/longbow/src/examples/tutorial/test_tutorial5.c b/longbow/src/examples/tutorial/test_tutorial5.c
new file mode 100644
index 00000000..c51ba7ac
--- /dev/null
+++ b/longbow/src/examples/tutorial/test_tutorial5.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+* /
+
+#include "tutorial.c"
+
+#include <LongBow/unit-test.h>
+
+
+LONGBOW_TEST_RUNNER(myTutorialTest)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
diff --git a/longbow/src/examples/tutorial/test_tutorial6.c b/longbow/src/examples/tutorial/test_tutorial6.c
new file mode 100644
index 00000000..a87c2466
--- /dev/null
+++ b/longbow/src/examples/tutorial/test_tutorial6.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+* /
+
+#include "tutorial.c"
+
+#include <LongBow/unit-test.h>
+
+
+LONGBOW_TEST_RUNNER(myTutorialTest)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+}
diff --git a/longbow/src/examples/tutorial/test_tutorial7.c b/longbow/src/examples/tutorial/test_tutorial7.c
new file mode 100644
index 00000000..25601997
--- /dev/null
+++ b/longbow/src/examples/tutorial/test_tutorial7.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 "tutorial.c"
+
+#include <LongBow/unit-test.h>
+
+
+LONGBOW_TEST_RUNNER(myTutorialTest)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest)
+{
+ 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;
+}
diff --git a/longbow/src/examples/tutorial/test_tutorial8.c b/longbow/src/examples/tutorial/test_tutorial8.c
new file mode 100644
index 00000000..35fad611
--- /dev/null
+++ b/longbow/src/examples/tutorial/test_tutorial8.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 "tutorial.c"
+
+#include <LongBow/unit-test.h>
+
+
+LONGBOW_TEST_RUNNER(myTutorialTest)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, alwaysSucceed);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
diff --git a/longbow/src/examples/tutorial/test_tutorial9.c b/longbow/src/examples/tutorial/test_tutorial9.c
new file mode 100644
index 00000000..c92fc459
--- /dev/null
+++ b/longbow/src/examples/tutorial/test_tutorial9.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+* /
+
+#include "tutorial.c"
+
+#include <LongBow/unit-test.h>
+
+
+LONGBOW_TEST_RUNNER(myTutorialTest)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, alwaysSucceed);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, alwaysSucceed)
+{
+ bool result = alwaysSucceed();
+
+ assertTrue(result, "This test must always succeed.");
+}
diff --git a/longbow/src/examples/tutorial/tutorial.c b/longbow/src/examples/tutorial/tutorial.c
new file mode 100755
index 00000000..ff296423
--- /dev/null
+++ b/longbow/src/examples/tutorial/tutorial.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.
+ */
+
+#include <unistd.h>
+#include <stdbool.h>
+#include <signal.h>
+
+static bool
+_privateFunction()
+{
+ return true;
+}
+
+bool
+alwaysSucceed()
+{
+ return _privateFunction();
+}
+
+bool
+alwaysFail()
+{
+ return false;
+}
+
+bool
+blowUp()
+{
+ char *p = 0;
+ *p = 0;
+
+ return true;
+}
diff --git a/longbow/src/python/.gitignore b/longbow/src/python/.gitignore
new file mode 100644
index 00000000..34921562
--- /dev/null
+++ b/longbow/src/python/.gitignore
@@ -0,0 +1,3 @@
+longbow-generate-about
+longbow-code
+longbow-preprocess
diff --git a/longbow/src/python/.project b/longbow/src/python/.project
new file mode 100644
index 00000000..fd327b61
--- /dev/null
+++ b/longbow/src/python/.project
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>LongBow-Python</name>
+ <comment></comment>
+ <projects>
+ <project>Longbow</project>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.python.pydev.PyDevBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.python.pydev.pythonNature</nature>
+ </natures>
+</projectDescription>
diff --git a/longbow/src/python/.pydevproject b/longbow/src/python/.pydevproject
new file mode 100644
index 00000000..f4a65975
--- /dev/null
+++ b/longbow/src/python/.pydevproject
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?eclipse-pydev version="1.0"?>
+
+<pydev_project>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+</pydev_project>
diff --git a/longbow/src/python/CMakeLists.txt b/longbow/src/python/CMakeLists.txt
new file mode 100644
index 00000000..33e2d70e
--- /dev/null
+++ b/longbow/src/python/CMakeLists.txt
@@ -0,0 +1,29 @@
+add_subdirectory(site-packages)
+
+install( FILES parc_uncrustify.cfg DESTINATION ${CMAKE_INSTALL_PREFIX}/etc )
+
+macro(AddLongBowPythonScript scriptFile)
+ configure_file(${ARGV0}.py ${ARGV0} @ONLY)
+ install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${ARGV0} COMPONENT library DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
+endmacro(AddLongBowPythonScript)
+
+set(ScriptList
+ longbow-doxygen-report
+ longbow-generate-about
+ longbow-preprocess
+ longbow-code
+ longbow-complexity-report
+ longbow-coverage-report
+ longbow-bytearray
+ longbow-ansigcov
+ longbow-name-report
+ longbow-size-report
+ longbow-style-report
+ longbow-test-run
+ longbow-test-suite
+ longbow-vocabulary-report
+ )
+
+foreach(script ${ScriptList})
+ AddLongBowPythonScript(${script})
+endforeach()
diff --git a/longbow/src/python/longbow-ansigcov.py b/longbow/src/python/longbow-ansigcov.py
new file mode 100755
index 00000000..c677ab2c
--- /dev/null
+++ b/longbow/src/python/longbow-ansigcov.py
@@ -0,0 +1,85 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+import sys
+import os
+import subprocess
+'''
+This programme takes a previously generated LongBow production (see longbow-preprocess.py) as input
+and generates corresponding C code as a template for a complete test runner for that production.
+'''
+
+ansiRed = "\x1b[31m";
+ansiGreen = "\x1b[32m";
+ansiYellow = "\x1b[33;1m";
+ansiOrange = "\x1b[33m";
+ansiReset = "\x1b[0m";
+
+
+def ANSITerminal_printchars(color, chars):
+ if color == "red":
+ return ansiRed + chars + ansiReset
+ if color == "green":
+ return ansiGreen + chars + ansiReset
+ if color == "yellow":
+ return ansiYellow + chars + ansiReset
+ if color == "orange":
+ return ansiOrange + chars + ansiReset
+ return chars
+
+
+class LongBowAnsi:
+ def __init__(self, input=sys.stdin):
+ self.input = input
+ return
+
+ def tokenise(self, line):
+ fields = line.split(":", 2)
+ fields[0] = fields[0].strip()
+ return fields
+
+ def colourise(self):
+ lines = self.input.read().splitlines()
+ for line in lines:
+ fields = self.tokenise(line)
+ if len(fields) == 3:
+ if fields[0] == "#####":
+ print ANSITerminal_printchars("red", fields[1]), ANSITerminal_printchars("red", fields[2])
+ pass
+ elif fields[0] == "$$$$$":
+ print ANSITerminal_printchars("yellow", fields[1]), ANSITerminal_printchars("yellow", fields[2])
+ pass
+ else:
+ print ANSITerminal_printchars("green", fields[1]), ANSITerminal_printchars("green", fields[2])
+ pass
+ pass
+ pass
+ return
+
+
+if __name__ == '__main__':
+ outputFileName = None
+
+ if len(sys.argv) != 2:
+ print "Usage: longbow-ansigov.py file.gcov"
+ sys.exit(1)
+
+ with open(sys.argv[1], 'r') as f:
+ longBowAnsi = LongBowAnsi(f)
+ longBowAnsi.colourise()
+ f.close()
+
+ pass
diff --git a/longbow/src/python/longbow-bytearray.py b/longbow/src/python/longbow-bytearray.py
new file mode 100755
index 00000000..30adfda3
--- /dev/null
+++ b/longbow/src/python/longbow-bytearray.py
@@ -0,0 +1,54 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+import sys
+import os
+
+def indent(count):
+ for i in range(0, count/2):
+ print " ",
+ return
+
+def print_interstitialspace(index):
+ if ((index + 1) % 8) == 0:
+ print " ",
+ if ((index + 1) % 16) == 0:
+ print ""
+ indent(4)
+ pass
+
+def printarray(array):
+ i = 0
+ for c in array:
+ print "0x%02x," % (c),
+ print_interstitialspace(i)
+ i = i + 1
+ pass
+
+ return
+
+if __name__ == '__main__':
+ with open(sys.argv[1], 'r') as f:
+
+ bytes = bytearray(f.read())
+ print len(bytes)
+ print "unsigned char bytes[] = {"
+ indent(4)
+ printarray(bytes)
+ print "\n};";
+ pass
+
+ f.close()
diff --git a/longbow/src/python/longbow-code.py b/longbow/src/python/longbow-code.py
new file mode 100755
index 00000000..8d5a72b6
--- /dev/null
+++ b/longbow/src/python/longbow-code.py
@@ -0,0 +1,208 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+import sys
+import os
+import subprocess
+'''
+This programme takes a previously generated LongBow production (see longbow-preprocess.py) as input
+and generates corresponding C code as a template for a complete test runner for that production.
+'''
+
+def sourceFileNameToShortName(sourceFileName):
+ '''
+ Given a path to a source file, return the name without any path components or suffix after the first '.' (inclusive).
+ '''
+ name = os.path.basename(sourceFileName)
+ return name.split(".")[0]
+
+def canonicalizeFunctionName(functionName):
+ '''
+ Given a function name that contains the initial '_' character,
+ strip it and return a canonicalised form of the same name suitable for invoking from a C source file.
+
+ This used to translate the typical function name mangling by the C compiler,
+ where foo() becomes _foo in the object file symbol table.
+ '''
+ if functionName[0] == "_":
+ functionName = functionName[1:]
+ return functionName
+
+class LongBowTestGenerator:
+ def __init__(self, output=sys.stdout):
+ self.output = output
+ return
+
+ def generateCode(self, testProduction):
+ testRunnerName = testProduction["name"]
+ sourceFileName = testProduction["files"]["sourceFile"]
+ objectFileName = testProduction["files"]["objectFile"]
+
+ self.filePrologue()
+ self.testRunnerPrologue(sourceFileName, objectFileName, testRunnerName, testProduction["testFixtures"])
+
+ for testFixture in testProduction["testFixtures"]:
+ fixtures = self.generateTestFixture(testProduction, testFixture)
+ pass
+
+ self.testRunnerEpilogue(sourceFileName, objectFileName, testRunnerName, testProduction["testFixtures"])
+ return
+
+ def filePrologue(self):
+ self.output.write("/*\n")
+ self.output.write(" *\n")
+ self.output.write(" */\n")
+ self.output.write("\n")
+ return
+
+ def testRunnerPrologue(self, sourceFileName, objectFileName, testRunnerName, testFixtures):
+ self.output.write("// Include the file(s) containing the functions to be tested.\n")
+ self.output.write("// This permits internal static functions to be visible to this Test Runner.\n")
+ self.output.write("#include \"%s\"\n" % (sourceFileName))
+ self.output.write("\n")
+ self.output.write("#include <LongBow/unit-test.h>\n")
+ self.output.write("\n")
+ self.output.write("LONGBOW_TEST_RUNNER(%s)\n" % (testRunnerName))
+ self.output.write("{\n")
+ self.output.write(" // The following Test Fixtures will run their corresponding Test Cases.\n")
+ self.output.write(" // Test Fixtures are run in the order specified here, but every test must be idempotent.\n")
+ self.output.write(" // Never rely on the execution order of tests or share state between them.\n")
+ for testFixture in testFixtures:
+ self.output.write(" LONGBOW_RUN_TEST_FIXTURE(%s);\n" % (testFixture["name"]))
+ pass
+ self.output.write("}\n")
+ self.output.write("\n" )
+ self.output.write("// The Test Runner calls this function once before any Test Fixtures are run.\n")
+ self.output.write("LONGBOW_TEST_RUNNER_SETUP(%s)\n" % (testRunnerName))
+ self.output.write("{\n")
+ self.output.write(" return LONGBOW_STATUS_SUCCEEDED;\n")
+ self.output.write("}\n")
+ self.output.write("\n")
+ self.output.write("// The Test Runner calls this function once after all the Test Fixtures are run.\n")
+ self.output.write("LONGBOW_TEST_RUNNER_TEARDOWN(%s)\n" % (testRunnerName))
+ self.output.write("{\n")
+ self.output.write(" return LONGBOW_STATUS_SUCCEEDED;\n")
+ self.output.write("}\n")
+ self.output.write("\n")
+ return
+
+ def testRunnerEpilogue(self, sourceFileName, objectFileName, testRunnerName, testFixtures):
+ self.output.write("int\n")
+ self.output.write("main(int argc, char *argv[])\n")
+ self.output.write("{\n")
+ self.output.write(" LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(%s);\n" % (testRunnerName))
+ self.output.write(" int exitStatus = longBowMain(argc, argv, testRunner, NULL);\n");
+ self.output.write(" longBowTestRunner_Destroy(&testRunner);\n");
+ self.output.write(" exit(exitStatus);\n");
+ self.output.write("}\n")
+ return
+
+ def generateTestFixture(self, testProduction, testFixture):
+ testFixtureName = testFixture["name"]
+
+ sourceFileName = testProduction["files"]["sourceFile"]
+ objectFileName = testProduction["files"]["objectFile"]
+
+ self.testFixturePrologue(sourceFileName, objectFileName, testFixtureName, testFixture["testSuites"])
+
+ for testSuite in testFixture["testSuites"]:
+ self.generateTestSuite(testProduction, testFixture, testSuite)
+ pass
+
+ self.testFixtureEpilogue(testProduction, testFixture, testSuite)
+ return [ testFixtureName ]
+
+ def testFixturePrologue(self, sourceFileName, objectFileName, testFixtureName, testSuites):
+ self.output.write("LONGBOW_TEST_FIXTURE(%s)\n" % (testFixtureName))
+ self.output.write("{\n")
+ for testSuite in testSuites:
+ for testCase in testSuite["testCases"]:
+ self.output.write(" LONGBOW_RUN_TEST_CASE(%s, %s);\n" % (testFixtureName, testCase))
+ pass
+ pass
+ self.output.write("}\n")
+ self.output.write("\n")
+ self.output.write("LONGBOW_TEST_FIXTURE_SETUP(%s)\n" % (testFixtureName))
+ self.output.write("{\n")
+ self.output.write(" return LONGBOW_STATUS_SUCCEEDED;\n")
+ self.output.write("}\n")
+ self.output.write("\n")
+ self.output.write( "LONGBOW_TEST_FIXTURE_TEARDOWN(%s)\n" % (testFixtureName))
+ self.output.write("{\n")
+ self.output.write(" return LONGBOW_STATUS_SUCCEEDED;\n")
+ self.output.write("}\n")
+ self.output.write("\n")
+ return
+
+ def testFixtureEpilogue(self, testProduction, testFixture, testSuite):
+ return
+
+ def generateTestSuite(self, testProduction, testFixture, testSuite):
+ for testCase in testSuite["testCases"]:
+ self.generateTestCase(testProduction, testFixture, testCase)
+ return
+
+ def generateTestCase(self, testProduction, testFixture, testCase):
+ self.output.write("LONGBOW_TEST_CASE(%s, %s)\n" % (testFixture["name"], testCase))
+ self.output.write("{\n")
+ self.output.write(" testUnimplemented(\"\");\n")
+ self.output.write("}\n")
+ self.output.write("\n")
+ return
+
+def getProductionSchema(fileName):
+ '''
+ Get the "production" schema produced by the preprocessor.
+ '''
+ f = open(fileName, "r")
+ text = f.read()
+ f.close()
+ return eval(text)
+
+def canonicalOutputFileName(production):
+ outputFileName = "test_" + sourceFileNameToShortName(production["files"]["sourceFile"]) + ".c"
+ return outputFileName
+
+def canonicalOutput(outputFileName):
+ if outputFileName == None:
+ return sys.stdout
+ open(outputFileName)
+
+if __name__ == '__main__':
+ '''
+@(#) longbow-code @VERSION@ @DATE@
+@(#) All Rights Reserved. Use is subject to license terms.
+ '''
+ outputFileName = None
+
+ if len(sys.argv) != 2:
+ print "Usage: longbow-code file.longbow"
+ sys.exit(1)
+
+ production = getProductionSchema(sys.argv[1])
+
+ if outputFileName == None:
+ outputFileName = canonicalOutputFileName(production)
+
+ if os.path.exists(outputFileName):
+ print "Refusing to overwrite the existing '%s'." % (outputFileName)
+ sys.exit(1)
+
+ outputFile = open(outputFileName, 'w')
+
+ generator = LongBowTestGenerator(outputFile)
+ generator.generateCode(production)
+ pass
diff --git a/longbow/src/python/longbow-complexity-report.py b/longbow/src/python/longbow-complexity-report.py
new file mode 100755
index 00000000..81ddcf72
--- /dev/null
+++ b/longbow/src/python/longbow-complexity-report.py
@@ -0,0 +1,213 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+
+import sys
+import argparse
+import itertools
+sys.path.append("@INSTALL_PYTHON_DIR@")
+sys.path.append("@DEPENDENCY_PYTHON_DIR@")
+import LongBow
+try:
+ import hfcca
+except ImportError:
+ print "HFCCA not found. You need to download hfcca.py and place it in a location"
+ print "where this script (python) can find it."
+ print "You can find a compatible version of hfcca at: "
+ print " https://headerfile-free-cyclomatic-complexity-analyzer.googlecode.com/files/hfcca.py"
+ print "And place it at: @INSTALL_PYTHON_DIR@"
+ print
+ print "... however, you should have run the ccnx-post-install script"
+ print " (from the ccnx distribution you got this from)"
+ sys.exit(1)
+
+def computeComplexityScore(complexity):
+ score = min(100.0 * abs(1.0 - float(complexity - 5) / 50.0), 100.0)
+ return score
+
+def csvFunctionResult(file, function):
+ score = computeComplexityScore(function.cyclomatic_complexity)
+ string = "complexity,%s,%s,%d,%d,%.2f" % (file.filename, function.name, function.start_line, function.cyclomatic_complexity, score)
+
+ LongBow.scorePrinter([90, 80], score, string)
+ return function.cyclomatic_complexity
+
+def csvFileComplexity(file):
+ score = computeComplexityScore(file.average_CCN)
+ string = "complexity,%s,,,%.2f,%.2f" % (file.filename, file.average_CCN, score)
+ LongBow.scorePrinter([90, 80], score, string)
+ return
+
+def csvFunction(fileInformationList):
+ for fileInformation in fileInformationList:
+ complexities = map(lambda function: csvFunctionResult(fileInformation, function), fileInformation)
+ return
+
+def csvSummary(fileInformationList):
+ map(lambda file: csvFileComplexity(file), fileInformationList)
+ return
+
+
+def textFunctionResult(file, function, maxFileNameLength, maxFunctionNameLength):
+ score = computeComplexityScore(function.cyclomatic_complexity)
+ format = "%-" + str(maxFileNameLength) + "s %-" + str(maxFunctionNameLength) + "s %6d %2d %6.2f"
+ string = format % (file.filename, function.name, function.start_line, function.cyclomatic_complexity, score)
+
+ LongBow.scorePrinter([90, 80], score, string)
+ return function.cyclomatic_complexity
+
+def textFileComplexity(file, maxFileNameLength):
+ score = computeComplexityScore(file.average_CCN)
+ string = ("%-" + str(maxFileNameLength) + "s %6.2f %6.2f") % (file.filename, file.average_CCN, score)
+ LongBow.scorePrinter([90, 80], score, string)
+ return
+
+def computeMaxFileNameLength(fileInformationList):
+ result = 0
+ for fileInformation in fileInformationList:
+ if len(fileInformation.filename) > result:
+ result = len(fileInformation.filename)
+ return result
+
+def computeMaxFunctionNameLength(fileInformationList):
+ result = 0
+ for fileInformation in fileInformationList:
+ if len(fileInformation.filename) > result:
+ result = len(fileInformation.filename)
+ return result
+
+def textFunction(fileInformationList):
+ maxFileNameLength = max(map(lambda fileInformation: len(fileInformation.filename), fileInformationList))
+ maxFunctionNameLength = max(map(lambda fileInformation: max(map(lambda function: len(function.name), fileInformation)), fileInformationList))
+
+ for fileInformation in fileInformationList:
+ complexities = map(lambda function: textFunctionResult(fileInformation, function, maxFileNameLength, maxFunctionNameLength), fileInformation)
+ return
+
+def textSummary(fileInformationList):
+ maxFileNameLength = max(map(lambda fileInformation: len(fileInformation.filename), fileInformationList))
+ map(lambda file: textFileComplexity(file, maxFileNameLength), fileInformationList)
+ return
+#
+# Recompute the file's average complexity as a floating point number.
+def recomputeFileComplexity(fileInformation):
+ complexities = map(lambda function: function.cyclomatic_complexity, fileInformation)
+ if len(complexities) > 0:
+ sum = reduce(lambda sum, complex: sum + complex, complexities)
+ fileInformation.average_CCN = float(sum) / len(fileInformation)
+ else:
+ fileInformation.average_CCN = 0
+ return fileInformation.average_CCN
+
+def recomputeFilesComplexity(fileInformationList):
+ return map(lambda fileInformation: recomputeFileComplexity(fileInformation), fileInformationList)
+
+def computeAverage(fileInformationList):
+ cyclomaticComplexity = map(lambda fileInformation : fileInformation.average_CCN, fileInformationList)
+ sum = reduce(lambda sum, x: sum + x, cyclomaticComplexity)
+ return float(sum) / float(len(cyclomaticComplexity))
+
+def main(argv):
+ desc = '''longbow-complexity-report @VERSION@ @DATE@
+ All Rights Reserved. Use is subject to license terms.
+
+Print the cyclomatic complexity of functions and files.
+
+The option --function displays the file name, function name,
+line number of the function, the cyclomatic complexity and a score ranging from 0 to 100.
+
+The default option --summary displays the file name,
+the average cyclomatic complexity of all functions in the file and
+a score ranging from 0 to 100.
+
+Input is either from a list of files supplied as command line parameters,
+or as a list of newline separated file names read from standard input.
+Output is a plain text (default) or comma-separated-value (CSV).
+
+Examples:
+
+% longbow-complexity-report *.[ch]
+
+Report conformance of the .c and .h files specified as command line parameters.
+
+% longbow-complexity-report -
+Report conformance of the .c and .h files read from standard input, one line per file.
+
+$ longbow-complexity-report parc_JSON.c
+parc_JSON.c 2.27 100.00
+$
+$ echo parc_JSON.c | longbow-complexity-report -o csv -
+complexity,parc_JSON.c,,,2.27,100.00
+$
+'''
+
+ parser = argparse.ArgumentParser(prog='longbow-complexity-report', formatter_class=argparse.RawDescriptionHelpFormatter, description=desc)
+ parser.add_argument('-s', '--summary', default=False, action="store_true", help="print the average complexity of each target file.")
+ parser.add_argument('-f', '--function', default=False, action="store_true", help="print the complexity of each function in each target file.")
+ parser.add_argument('-', '--stdin', default=False, action="store_true", required=False, help="read the list of files from standard input rather than the command line.")
+ parser.add_argument('-a', '--average', default=False, action="store_true", required=False, help="display only the simple average of the average complexity of each target file.")
+ parser.add_argument('-o', '--output', default="text", action="store", required=False, type=str, help="the output format: \"text\" or \"csv\"")
+ parser.add_argument("files", help="Files to check", nargs="*")
+
+ args = parser.parse_args()
+
+ targets = []
+
+ if args.stdin:
+ for line in sys.stdin:
+ t = line.strip()
+ if (len(t) > 0):
+ targets.append(t)
+ else:
+ targets = args.files
+
+ if (len(targets) == 0):
+ print >> sys.stderr, "Error: No files to analyze. See %s -h" % (sys.argv[0])
+ sys.exit(1)
+
+ # If nothing was specified, print the summary as a default
+ if args.summary == False and args.function == False and args.average == False:
+ args.summary = True
+
+ options, arguments = hfcca.createHfccaCommandLineParser().parse_args(args=[argv[0]])
+ result = hfcca.analyze(targets, options)
+
+ # Convert from that iterator to a simple list...
+ fileInformationList = map(lambda x : x, result)
+
+ recomputeFilesComplexity(fileInformationList)
+
+ if args.function:
+ if args.output == "text":
+ textFunction(fileInformationList)
+ else:
+ csvFunction(fileInformationList)
+
+ if args.summary:
+ if args.output == "text":
+ textSummary(fileInformationList)
+ else:
+ csvSummary(fileInformationList)
+
+ if args.average:
+ print "%.2f" % computeAverage(fileInformationList)
+
+if __name__ == "__main__":
+ '''
+@(#) longbow-complexity-report @VERSION@ @DATE@
+@(#) All Rights Reserved. Use is subject to license terms.
+'''
+ main(sys.argv)
diff --git a/longbow/src/python/longbow-coverage-report.py b/longbow/src/python/longbow-coverage-report.py
new file mode 100755
index 00000000..4a0a86ab
--- /dev/null
+++ b/longbow/src/python/longbow-coverage-report.py
@@ -0,0 +1,87 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+import sys
+import argparse
+
+sys.path.append("@INSTALL_PYTHON_DIR@")
+sys.path.append("@DEPENDENCY_PYTHON_DIR@")
+sys.path.append("../site-packages/longbow/")
+import CoverageReport
+
+
+if __name__ == '__main__':
+ '''
+@(#) longbow-coverage-report @VERSION@ @DATE@
+@(#) All Rights Reserved. Use is subject to license terms.
+'''
+ description = '''
+longbow-coverage-report @VERSION@ @DATE@
+All Rights Reserved. Use is subject to license terms.
+
+Report on the code coverage of tests.
+
+The source files or executables to analyse are supplied as command line parameters,
+or as a list of newline separated file names read from standard input.
+
+Output is plain-text (default --output text) or a CSV file (--output csv)
+reporting the results.
+
+Results are:
+ An average of all files specified (--average)
+ A one line summary of all files specified (--summary)
+ A listing of the original source file, colorized showing tested and non-tested lines.
+ '''
+ parser = argparse.ArgumentParser(prog='longbow-coverage-report',
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ description=description)
+ parser.add_argument('-', '--stdin', default=False, action="store_true", required=False,
+ help="Read the list of files from standard input.")
+ parser.add_argument('-s', '--summary', default=False, action="store_true", required=False,
+ help="Display the score for each file (excluding test source files).")
+ parser.add_argument('-a', '--average', default=False, action="store_true", required=False,
+ help="Display the average score for all C source files (excluding test source files).")
+ parser.add_argument('-o', '--output', default="text", action="store", required=False, type=str,
+ help="Set the output format: \"text\" or \"csv\"")
+ parser.add_argument('-v', '--visual', default=False, action="store_true", required=False,
+ help="Colorize the original source code showing coverage")
+ parser.add_argument('-x', '--explain', default=False, action="store_true", required=False,
+ help="Display information about the collection of coverage information (guru mode).")
+ parser.add_argument('-d', '--distribution', default="[95, 90]", action="store", required=False, type=str,
+ help="A list containing the score distributions for pretty-printing. Default [95, 90]")
+ parser.add_argument('-T', '--includeTestSources', default=False, action="store_true", required=False,
+ help="Include analysis of the test sources. Default False")
+ parser.add_argument('-t', '--testDir', default="", action="store", required=False, type=str,
+ help="Directory hint for locating test files.")
+
+ parser.add_argument("files", help="Files to check", nargs="*")
+
+ args = parser.parse_args()
+
+ if not args.summary and not args.average and not args.visual and not args.explain:
+ args.summary = True
+
+ fileNames = []
+
+ if args.stdin:
+ for line in sys.stdin:
+ t = line.strip()
+ if len(t) > 0:
+ fileNames.append(t)
+ else:
+ fileNames = args.files
+
+ CoverageReport.commandLineMain(args, fileNames, args.testDir)
diff --git a/longbow/src/python/longbow-doxygen-report.py b/longbow/src/python/longbow-doxygen-report.py
new file mode 100755
index 00000000..1b303f91
--- /dev/null
+++ b/longbow/src/python/longbow-doxygen-report.py
@@ -0,0 +1,166 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+
+import sys
+import os
+import pprint
+import subprocess
+import difflib
+import csv
+import argparse
+sys.path.append("@INSTALL_PYTHON_DIR@")
+sys.path.append("@DEPENDENCY_PYTHON_DIR@")
+import LongBow
+
+def concatenateContinuationLines(lines):
+ '''
+ Parse doxygen log lines.
+ Lines that are indented by a space are continutations of the previous line.
+ '''
+ result = list()
+ accumulator = ""
+ for line in lines:
+ line = line.rstrip()
+ if line.startswith(" ") == False and line.startswith(" ") == False:
+ if len(accumulator) > 0:
+ result.append(accumulator)
+ accumulator = line
+ else:
+ accumulator = accumulator + " " + line.lstrip()
+
+ result.append(accumulator)
+
+ return result
+
+def parseLine(line):
+ result = None
+ if not line.startswith("<"):
+ fields = line.split(":")
+ if len(fields) >= 4:
+ result = { "fileName" : fields[0].strip(),
+ "lineNumber" : int(fields[1].strip()),
+ "type" : "documentation",
+ "severity" : fields[2].strip(),
+ "message" : " ".join(fields[3:]).strip()}
+ elif line.startswith("error"):
+ print line
+ elif len(line) > 0:
+ print "Consider using doxygen -s:", line
+
+ return result
+
+def canonicalize(lines):
+ lines = concatenateContinuationLines(lines)
+ parsedLines = map(lambda line: parseLine(line), lines)
+ parsedLines = filter(lambda line: line != None, parsedLines)
+ return parsedLines
+
+def organize(entries):
+ result = dict()
+
+ for entry in entries:
+ if not entry["fileName"] in result:
+ result[entry["fileName"]] = dict()
+
+ entryByFile = result[entry["fileName"]]
+
+ if not str(entry["lineNumber"]) in entryByFile:
+ entryByFile[str(entry["lineNumber"])] = list()
+ if not entry in entryByFile[str(entry["lineNumber"])]:
+ entryByFile[str(entry["lineNumber"])].append(entry)
+
+ return result
+
+def textualSummary(distribution, documentation):
+ maxWidth = 0
+ for entry in documentation:
+ if len(entry) > maxWidth:
+ maxWidth = len(entry)
+
+ formatString ="%-" + str(maxWidth) + "s %8d %8d %.2f%%"
+ for entry in documentation:
+ badLines = len(documentation[entry])
+ totalLines = LongBow.countLines(entry)
+ score = float(totalLines - badLines) / float(totalLines) * 100.0
+ LongBow.scorePrinter(distribution, score, formatString % (entry, totalLines, badLines, score))
+ return
+
+def textualAverage(distribution, documentation, format):
+ sum = 0.0
+
+ for entry in documentation:
+ badLines = len(documentation[entry])
+ totalLines = LongBow.countLines(entry)
+ score = float(totalLines - badLines) / float(totalLines) * 100.0
+ sum = sum + score
+
+ if len(documentation) == 0:
+ averageScore = 100.0
+ else:
+ averageScore = sum / float(len(documentation))
+
+ LongBow.scorePrinter(distribution, averageScore, format % averageScore)
+
+def csvSummary(distribution, documentation):
+ formatString ="documentation,%s,%d,%d,%.2f%%"
+ for entry in documentation:
+ badLines = len(documentation[entry])
+ totalLines = LongBow.countLines(entry)
+ score = float(totalLines - badLines) / float(totalLines) * 100.0
+ LongBow.scorePrinter(distribution, score, formatString % (entry, totalLines, badLines, score))
+ return
+
+def main(argv):
+ parser = argparse.ArgumentParser(prog='longbow-doxygen-report', formatter_class=argparse.RawDescriptionHelpFormatter, description="")
+ parser.add_argument('-l', '--doxygenlog', default=False, action="store", required=True, type=str, help="The doxygen output log to use.")
+ parser.add_argument('-s', '--summary', default=False, action="store_true", required=False, help="Produce the score for each file")
+ parser.add_argument('-a', '--average', default=False, action="store_true", required=False, help="Produce the simple average of all scores.")
+ parser.add_argument('-d', '--distribution', default="[100, 95]", action="store", required=False, type=str, help="A list containing the score distributions for pretty-printing")
+ parser.add_argument('-o', '--output', default="text", action="store", required=False, type=str, help="The required output format. text, csv")
+
+ args = parser.parse_args()
+
+ if not args.summary and not args.average:
+ args.summary = True
+
+ with open(args.doxygenlog, 'r') as f:
+ lines = f.readlines()
+
+ lines = canonicalize(lines)
+
+ result = organize(lines)
+
+ pp = pprint.PrettyPrinter(indent=4)
+ #pp.pprint(result)
+
+ distribution = eval(args.distribution)
+ if args.summary:
+ if args.output == "text":
+ textualSummary(distribution, result)
+ else:
+ csvSummary(distribution, result)
+
+ if args.average:
+ textualAverage(distribution, result, "%.2f")
+
+
+if __name__ == '__main__':
+ '''
+@(#) longbow-doxygen-report @VERSION@ @DATE@
+@(#) All Rights Reserved. Use is subject to license terms.
+ '''
+ main(sys.argv)
diff --git a/longbow/src/python/longbow-generate-about.py b/longbow/src/python/longbow-generate-about.py
new file mode 100755
index 00000000..437102a3
--- /dev/null
+++ b/longbow/src/python/longbow-generate-about.py
@@ -0,0 +1,289 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+import os
+import sys
+import string
+import datetime
+import argparse
+sys.path.append("@INSTALL_PYTHON_DIR@")
+sys.path.append("@DEPENDENCY_PYTHON_DIR@")
+import FileUtil
+
+whatLineToken = "@(#)"
+
+def translateCCharacter(character):
+ result = character
+
+ if character == '\t':
+ result = "\\t"
+ elif character == "\n":
+ result = "\\n"
+ elif character == "\"":
+ result = "\\\""
+ elif character == "\'":
+ result = "\\'"
+
+ return result
+
+
+def makeWhatLine(line):
+ return "@(#)" + line
+
+def createCString(string):
+ if string is None:
+ result = "None"
+ else:
+ result = "".join(map(lambda character: translateCCharacter(character), string))
+ return result
+
+def createQuotedCString(string):
+ return "\"%s\"" % createCString(string)
+
+def cIdentifier(name):
+ translation = string.maketrans("-!@#$%^&*()_-+=[]{}|;:<>,./?", "____________________________")
+ return name.translate(translation)
+
+
+def validateArgument(arg):
+ '''
+ If the given parameter is equal to '-' return None, otherwise return the parameter.
+ '''
+ if arg == "-":
+ return None
+ return arg
+
+
+class LongBowGenerateAboutHFile:
+ def __init__(self, prefix):
+ self.prefix = prefix
+ return
+
+ def headerdocFunction(self, functionName, OneLineDescription, returns):
+ result = "/**\n"
+ result += " * %s\n" % OneLineDescription
+ result += " *\n"
+ result += " * @return %s\n" % returns
+ result += " */\n"
+ return result
+
+ def FileName(self):
+ return self.prefix + "_About.h"
+
+ def Name(self):
+ functionName = "%sAbout_Name" % self.prefix
+ result = self.headerdocFunction(functionName, "Return the name as a C string.", "The name as a C string.")
+ result += "const char *%s(void);\n" % functionName
+ return result
+
+ def Version(self):
+ functionName = "%sAbout_Version" % self.prefix
+ result = self.headerdocFunction(functionName, "Return the version as a C string.", "The version as a C string.")
+ result += "const char *%s(void);\n" % functionName
+ return result
+
+ def About(self):
+ functionName = "%sAbout_About" % self.prefix
+ result = self.headerdocFunction(functionName, "Return the About text as a C string.", "The About text as a C string.")
+ result += "const char *%s(void);\n" % functionName
+ return result
+
+ def MiniNotice(self):
+ functionName = "%sAbout_MiniNotice" % self.prefix
+ result = self.headerdocFunction(functionName,
+ "Return the minimum copyright notice as a C string.",
+ "The minimum copyright notice as a C string.")
+ result += "const char *%s(void);\n" % functionName
+ return result
+
+ def ShortNotice(self):
+ functionName = "%sAbout_ShortNotice" % self.prefix
+ result = self.headerdocFunction(functionName,
+ "Return the short copyright notice as a C string.",
+ "The short copyright notice as a C string.")
+ result += "const char *%s(void);\n" % functionName
+ return result
+
+ def LongNotice(self):
+ functionName = "%sAbout_LongNotice" % self.prefix
+ result = self.headerdocFunction(functionName,
+ "Return the long copyright notice as a C string.",
+ "The long copyright notice as a C string.")
+ result += "const char *%s(void);\n" % functionName
+ return result
+
+ def WhatString(self):
+ result = "/**\n"
+ result += " * Embedded string containing information for the what(1) command.\n"
+ result += " *\n"
+ result += " */\n"
+ result += "extern const char *%s_What;\n" % (self.prefix)
+ return result
+
+ def __str__(self):
+ result = "// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.\n"
+ result += "// longbow-generate-about @VERSION@ @DATE@\n\n"
+ result += "#ifndef %s_About_h\n" % (self.prefix)
+ result += "#define %s_About_h\n" % (cIdentifier(self.prefix))
+ result += self.WhatString() + "\n"
+ result += self.Name() + "\n"
+ result += self.Version() + "\n"
+ result += self.About() + "\n"
+ result += self.MiniNotice() + "\n"
+ result += self.ShortNotice() + "\n"
+ result += self.LongNotice() + "\n"
+ result += "#endif // %s_About_h\n" % (cIdentifier(self.prefix))
+ return result
+
+ def writeFile(self):
+ with open(self.FileName(), "w") as myfile:
+ myfile.write(str(self))
+ return
+
+class LongBowGenerateAboutCFile:
+ def __init__(self, args):
+ self.prefix = args.prefix
+ self.name = args.name
+ self.version = validateArgument(args.version)
+ self.miniNotice = ""
+ self.shortNotice = ""
+ self.longNotice = ""
+ self.about = None
+ self.what = None
+
+ self.args = args
+
+ self.miniNotice = FileUtil.readFileString(args.miniNotice)
+ self.shortNotice = FileUtil.readFileString(args.shortNotice)
+ self.longNotice = FileUtil.readFileString(args.longNotice)
+
+ self.buildDate = datetime.datetime.utcnow().isoformat()
+
+ if self.version == None:
+ self.version = " RELEASE_VERSION "
+
+ if self.about == None:
+ self.about = createQuotedCString("%s " % (self.name)) + \
+ self.version + \
+ createQuotedCString(" %s" % (self.buildDate)) + " " + \
+ createQuotedCString("\n%s" % (self.miniNotice))
+
+ if self.what == None:
+ if self.miniNotice != None:
+ notice = "\n".join(map(lambda line: "\t" + line, self.miniNotice.split("\n")[:-1]))
+ else:
+ notice = ""
+ self.what = createQuotedCString(whatLineToken) + " " + \
+ createQuotedCString(self.name + " ") + " " + \
+ self.version + " " + \
+ createQuotedCString(" " + self.buildDate) + "\n" + \
+ createQuotedCString(whatLineToken) + " " + \
+ createQuotedCString(notice)
+ return
+
+ def FileName(self):
+ return self.prefix + "_About.c"
+
+ def Name(self):
+ functionName = "%sAbout_Name" % self.prefix
+ return self.boilerPlateFunction(functionName, createQuotedCString(self.name))
+
+ def Version(self):
+ functionName = "%sAbout_Version" % self.prefix
+ return self.boilerPlateFunction(functionName, self.version)
+
+ def About(self):
+ functionName = "%sAbout_About" % self.prefix
+ return self.boilerPlateFunction(functionName, self.about)
+
+ def MiniNotice(self):
+ functionName = "%sAbout_MiniNotice" % self.prefix
+ return self.boilerPlateFunction(functionName, createQuotedCString(self.miniNotice))
+
+ def ShortNotice(self):
+ functionName = "%sAbout_ShortNotice" % self.prefix
+ return self.boilerPlateFunction(functionName, createQuotedCString(self.shortNotice))
+
+ def LongNotice(self):
+ functionName = "%sAbout_LongNotice" % self.prefix
+ return self.boilerPlateFunction(functionName, createQuotedCString(self.longNotice))
+
+ def WhatString(self):
+ return "const char *%s_What = %s;\n" % (self.prefix, self.what)
+
+ def boilerPlateFunction(self, functionName, string):
+ result = "const char *\n%s(void)\n" % functionName
+ result += "{\n"
+ result += " return %s;\n" % string
+ result += "}\n"
+ return result
+
+ def __str__(self):
+ result = "// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.\n"
+ result += "// longbow-generate-about @VERSION@ @DATE@\n\n"
+ result += "#include \"%s_About.h\"\n\n" % self.prefix
+ result += self.WhatString() + "\n"
+ result += self.Name() + "\n"
+ result += self.Version() + "\n"
+ result += self.About() + "\n"
+ result += self.MiniNotice() + "\n"
+ result += self.ShortNotice() + "\n"
+ result += self.LongNotice() + "\n"
+ return result
+
+ def writeFile(self):
+ with open(self.FileName(), "w") as myfile:
+ myfile.write(str(self))
+ return
+
+if __name__ == '__main__':
+ desc = '''
+@(#) longbow-generate-about @VERSION@ @DATE@
+@(#) All Rights Reserved. Use is subject to license terms.
+
+Generate C code conforming to the About contract.
+
+Create a .c and .h file pair with the specified prefix.
+For the prefix 'xyzzy', the file names are 'xyzzy_About.c' and 'xyzzy_About.h' respectively.
+
+The functions defined are:
+
+const char *xyzzyAbout_Name(void)
+const char *xyzzyAbout_Version(void)
+const char *xyzzyAbout_About(void)
+const char *xyzzyAbout_MiniNotice(void)
+const char *xyzzyAbout_ShortNotice(void)
+const char *xyzzyAbout_LongNotice(void)
+
+And the constant string const char *xyzzy_What;
+ '''
+
+ parser = argparse.ArgumentParser(prog='longbow-generate-about', formatter_class=argparse.RawDescriptionHelpFormatter, description=desc)
+
+ parser.add_argument("prefix", help="The file name and function name prefix.")
+ parser.add_argument("name", help="The name of the entity this is about.")
+ parser.add_argument("version", help="The version of the entity this is about.")
+ parser.add_argument("miniNotice", help="The name of the file containing the smallest copyright or attribution notice.")
+ parser.add_argument("shortNotice", help="The name of the file containing a short copyright or attribution notice.")
+ parser.add_argument("longNotice", help="The name of the file containing a full copyright or attribution notice.")
+
+ args = parser.parse_args()
+
+ hfile = LongBowGenerateAboutHFile(args.prefix)
+ hfile.writeFile()
+
+ cfile = LongBowGenerateAboutCFile(args)
+ cfile.writeFile()
diff --git a/longbow/src/python/longbow-name-report.py b/longbow/src/python/longbow-name-report.py
new file mode 100755
index 00000000..3daca949
--- /dev/null
+++ b/longbow/src/python/longbow-name-report.py
@@ -0,0 +1,91 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+
+import os
+import sys
+import argparse
+
+sys.path.append("../site-packages/longbow/")
+sys.path.append("@INSTALL_PYTHON_DIR@")
+import NameReport
+
+if __name__ == '__main__':
+ '''
+ @(#) name-report @VERSION@ @DATE@
+ @(#) All Rights Reserved. Use is subject to license terms.
+ '''
+ desc = '''
+Print a score representing the percentage of compliance with the naming conventions for one or more C source and object files.
+
+$ ./longbow-name-report parc_Object.c
+/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-names 100.00 enum-names 100.0 typedef-names 100.0
+$
+$ echo parc_Object.c | ./parc-name-grade -
+/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-names 100.00 enum-names 100.0 typedef-names 100.0
+$
+
+Default Output (--summary):
+namespace, module-name[, topic, score]
+
+namespace: Namespace of the file, like `parc`
+module-name: The name of the file, like `parc_ArrayList.c`
+topic: The name of the topic: valid-name, function-name-conformance, or enum-name-conformance
+score: A context-sensitive value related to the topic (valid-name: True/False, function/enum-name-conformance: 0-100)
+
+Finegrain Output (--finegrain):
+/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-names 100.00 enum-names 100.0 typedef-names 100.0
+/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_Acquire 100.0
+/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_AssertValid 100.0
+/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_Compare 100.0
+/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_Copy 100.0
+/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_Create 100.0
+/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_Display 100.0
+/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_Equals 100.0
+/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_GetReferenceCount 100.0
+/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_HashCode 100.0
+/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_Release 100.0
+/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_TestAcquireContractRaw 100.0
+/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_ToJSON 100.0
+/Users/cwood/Projects/DistilleryBranches/Case1073/LibpgetEnumerationsFromFilesarc/parc/algol parc_Object function-name parcObject_ToString 100.0
+/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object typedef-name _ObjectHeader 100.0
+'''
+
+ parser = argparse.ArgumentParser(prog='longbow-name-report', formatter_class=argparse.RawDescriptionHelpFormatter, description=desc)
+ parser.add_argument('-a', '--average', default=False, action="store_true", help="Print an average summary of the naming conformance results for all modules")
+ parser.add_argument('-s', '--summary', default=False, action="store_true", help="Print a summary of the naming conformance results for each module")
+ parser.add_argument('-f', '--finegrain', default=False, action="store_true", help="Print the individual results for each function, typedef, and enumeration in each module.")
+ parser.add_argument('-o', '--output', default="text", action="store", required=False, type=str, help="the output format: \"text\" or \"csv\"")
+ parser.add_argument('-d', '--distribution', default="[99, 90]", action="store", required=False, type=str, help="a list containing the score distributions for pretty-printing. Default [99, 90]")
+ parser.add_argument('-t', '--trace', default=False, action="store_true", help="Turn on exception tracing to debug an issue with the tool.")
+ parser.add_argument('-', '--stdin', default=False, action="store_true", required=False, help="Read the list of files from standard input.")
+ parser.add_argument('-p', '--opath', default="", action="store", required=False, type=str, help="Specify the path for object files, can be a path to a static library.")
+ parser.add_argument("files", help="Files to check", nargs="*")
+
+ args = parser.parse_args()
+
+ targets = []
+ if args.stdin:
+ for line in sys.stdin:
+ targets.append(line.strip())
+ else:
+ targets = args.files
+
+ if (len(targets) == 0):
+ parser.print_usage()
+ sys.exit(1)
+
+ NameReport.commandLineMain(args, targets, args.opath)
diff --git a/longbow/src/python/longbow-preprocess.py b/longbow/src/python/longbow-preprocess.py
new file mode 100755
index 00000000..12c01c2a
--- /dev/null
+++ b/longbow/src/python/longbow-preprocess.py
@@ -0,0 +1,153 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+
+import sys
+import os
+import subprocess
+import pprint
+
+def sourceFileNameToName(sourceFileName):
+ '''
+ Given the path to a source file, return the name without any path components or trailing suffix.
+ '''
+ name = os.path.basename(sourceFileName)
+ return name.split(".")[0]
+
+def canonicalizeFunctionName(functionName):
+ '''
+ Given a function name that contains the initial '_' character,
+ strip it and return a canonicalised form of the same name suitable for a source file.
+ '''
+ if functionName[0] == "_":
+ functionName = functionName[1:]
+ return functionName
+
+def isReservedName(functionName):
+ '''
+ Given a canonicalized name, determine if it is a reserved name according to ISO/IEC 9899:2011 and ANSI Sec. 4.1.2.1,
+ identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
+ '''
+ if functionName[0] == '_' and functionName[1] == '_':
+ return True
+ elif functionName[0] == '_' and functionName[1].isupper():
+ return True
+
+ return False
+
+
+def getDarwinTestableFunctions(sourceFileName, objectFileName):
+ '''
+ '''
+ command = [ "/usr/bin/nm", "-Um", objectFileName ]
+
+ output = subprocess.check_output(command)
+ lines = output.splitlines()
+
+ external = []
+ internal = []
+ for line in lines:
+ fields = line.split(" ")
+ if fields[1] == "(__TEXT,__text)":
+ functionName = canonicalizeFunctionName(fields[3])
+
+ if isReservedName(functionName):
+ print "Ignoring function with a ISO/IEC 9899:2011 and ANSI Sec. 4.1.2.1 reserved name: ", functionName
+ else:
+ if fields[2] == "external":
+ external.append( ( functionName ) )
+ else:
+ internal.append( ( functionName ) )
+ pass
+ pass
+ pass
+
+ external.sort()
+ internal.sort()
+ return { "Static": internal, "Global" : external }
+
+def testCases(functionList):
+ '''
+ '''
+ return { "testCases" : functionList }
+
+def testSuite(testCases):
+ '''
+ A Test Suite is comprised of one or more Test Cases
+ '''
+ if testCases == None or len(testCases) == 0:
+ return None
+ return [ testCases ]
+
+def testFixture(testFixtureName, testSuites):
+ '''
+ A Test Fixture contains an initial setup function, one or more Test Suites, and a final tear-down function.
+ '''
+ if testSuites == None:
+ return None
+ return { "name" : testFixtureName, "testSuites" : testSuites }
+
+def testRunner(testRunnerName, files, testFixtures):
+ '''
+ A Test Runner contains one or more Test Fixtures.
+ '''
+ testFixtures = [x for x in testFixtures if x is not None]
+ return { "name" : testRunnerName, "files" : files, "testFixtures" : testFixtures }
+
+def computeFileNames(argv):
+ """ Given an argument list, compute the file names to use for code generation.
+
+
+ """
+ if (argv[1].endswith(".c")):
+ return (argv[1], argv[2], sourceFileNameToName(argv[1]) + ".longbow")
+
+ return (argv[1]+".c", argv[1]+".o", sourceFileNameToName(argv[1]) + ".longbow")
+
+if __name__ == '__main__':
+ '''
+ @(#) longbow-preprocess @VERSION@ @DATE@
+ @(#) All Rights Reserved. Use is subject to license terms.
+'''
+ if len(sys.argv) <= 1:
+ print "Usage: longbow-preprocess (sourceFileName objectFileName) | (fileNamePrefix)"
+ print
+ print "Generate a plain-text intermediate form for a LongBow test case generated from"
+ print "a specified source and object file. Use longbow-code to produce a LongBow"
+ print "test runner based upon the intermediate form."
+ sys.exit(1)
+
+ fileNames = computeFileNames(sys.argv)
+
+ sourceFileName = fileNames[0]
+ objectFileName = fileNames[1]
+ outputFileName = fileNames[2]
+
+ functionDictionary = getDarwinTestableFunctions(sourceFileName, objectFileName)
+
+ testRunnerName = sourceFileNameToName(sourceFileName)
+
+ testFixtures = map(lambda(fixtureType):
+ testFixture(fixtureType, testSuite(testCases(functionDictionary[fixtureType]))), functionDictionary)
+
+ files = { "sourceFile" : sourceFileName, "objectFile" : objectFileName }
+ result = testRunner(testRunnerName, files, testFixtures)
+
+ out = open(outputFileName, "w")
+ pp = pprint.PrettyPrinter(indent=4, width=132, depth=None, stream=out)
+ pp.pprint(result)
+ out.close()
+ pass
diff --git a/longbow/src/python/longbow-size-report.py b/longbow/src/python/longbow-size-report.py
new file mode 100755
index 00000000..fd4ae76c
--- /dev/null
+++ b/longbow/src/python/longbow-size-report.py
@@ -0,0 +1,131 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+
+import sys
+import os
+import subprocess
+import difflib
+import csv
+import argparse
+sys.path.append("@INSTALL_PYTHON_DIR@")
+import LongBow
+from pprint import pprint
+
+def textOutputFile(file, maximumFileNameLength):
+ format = "%-" + str(maximumFileNameLength) + "s %6d"
+ print format % (file[0], file[1])
+ return
+
+def textSummary(files):
+ maximumFileNameLength = max(map(lambda file: len(file[0]), files))
+ map(lambda file: textOutputFile(file, maximumFileNameLength), files)
+ return
+
+def csvOutputFile(file):
+ format = "size,%s,%d"
+ print format % (file[0], file[1])
+ return
+
+def csvSummary(files):
+ map(lambda file: csvOutputFile(file), files)
+ return
+
+def textTotal(files):
+ total = sum(map(lambda file: file[1], files))
+ print total
+ return
+
+def csvTotal(files):
+ total = sum(map(lambda file: file[1], files))
+ print total
+ return
+
+def main():
+ desc = '''
+Report on number of lines of one or more C source or header files.
+
+Input is either from a list of files supplied as command line parameters,
+or as a list of newline separated file names read from standard input.
+Output is a plain text (default) or a CSV file reporting
+the file name and the total number of lines in the file.
+
+Usage:
+
+% longbow-size-report *.[ch]
+
+Report the number of lines in .c and .h files specified as command line parameters.
+
+% longbow-size-report -
+Read the lists of files from standard input, one file per line.
+
+$ longbow-size-report parc_JSON.c
+parc_JSON.c 239
+$
+$
+$ echo parc_JSON.c | longbow-size-report -o csv -
+parc_JSON.c,239
+$
+'''
+
+ parser = argparse.ArgumentParser(prog='longbow-size-report', formatter_class=argparse.RawDescriptionHelpFormatter, description=desc)
+ parser.add_argument('-', '--stdin', default=False, action="store_true", required=False, help="read the list of files from standard input.")
+ parser.add_argument('-s', '--summary', default=False, action="store_true", required=False, help="display the number of lines for each file")
+ parser.add_argument('-t', '--total', default=False, action="store_true", required=False, help="display the total number of lines for all files")
+ parser.add_argument('-o', '--output', default="text", action="store", required=False, type=str, help="the output format: \"text\" or \"csv\"")
+
+ parser.add_argument("files", help="Files to check", nargs="*")
+
+ args = parser.parse_args()
+
+ if args.summary == False and args.total == False:
+ args.summary = True
+
+ targets = []
+
+ if args.stdin:
+ for line in sys.stdin:
+ t = line.strip()
+ if len(t) > 0:
+ targets.append(t)
+ else:
+ targets = args.files
+
+ if len(targets) == 0:
+ parser.print_usage()
+ sys.exit(1)
+
+ files = map(lambda fileName: [ fileName, LongBow.countLines(fileName)], targets)
+ total = sum(map(lambda element: element[1], files))
+
+ if args.summary:
+ if args.output == "text":
+ textSummary(files)
+ else:
+ csvSummary(files)
+
+ if args.total:
+ if args.output == "text":
+ textTotal(files)
+ else:
+ csvTotal(files)
+
+if __name__ == '__main__':
+ '''
+ @(#) longbow-size-report @VERSION@ @DATE@
+ @(#) All Rights Reserved. Use is subject to license terms.
+ '''
+ main()
diff --git a/longbow/src/python/longbow-style-report.py b/longbow/src/python/longbow-style-report.py
new file mode 100755
index 00000000..05b8fbde
--- /dev/null
+++ b/longbow/src/python/longbow-style-report.py
@@ -0,0 +1,99 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+
+import sys
+import argparse
+
+sys.path.append("@INSTALL_PYTHON_DIR@")
+sys.path.append("@DEPENDENCY_PYTHON_DIR@")
+sys.path.append("../site-packages/longbow/")
+import StyleReport
+
+if __name__ == '__main__':
+ '''
+@(#) longbow-code @VERSION@ @DATE@
+ @(#) All Rights Reserved. Use is subject to license terms.
+'''
+ desc = '''
+Report on style conformance for one or more C source or header files.
+
+Input is either from a list of files supplied as command line parameters,
+or as a list of newline separated file names read from standard input.
+Reports are:
+--summary A one line per file report of the file name, number of lines, number of non-compliant lines, and a score.
+--average A single line output of the average of all scores.
+--total A single line of output of the percentage of all compliant lines to the total number of lines in all files.
+--visual A visual representation of the style check.
+
+For each of these reports, the output format is specified by:
+--output text Display text on standard output
+--output csv Display a list of comma-separated values on standard output.
+--output gui Use a graphical user interface if possible.
+
+The visual report displays either a colorized, line by line output of
+the differences between the original source file it's exemplar (-o text),
+or displays a file-merge application for interactive use ()-o gui)
+
+Example:
+
+% longbow-style-report *.[ch]
+
+Report conformance of the .c and .h files specified as command line parameters.
+
+% longbow-style-report -
+Report conformance of the .c and .h files read from standard input, one line per file.
+
+$ longbow-style-report parc_JSON.c
+parc_JSON.c 239 0 100.00$
+$
+$ echo parc_JSON.c | longbow-style-report -
+parc_JSON.c,239,0,100.00
+$
+'''
+
+ parser = argparse.ArgumentParser(prog='longbow-style-report', formatter_class=argparse.RawDescriptionHelpFormatter, description=desc)
+ parser.add_argument('-', '--stdin', default=False, action="store_true", required=False, help="read the list of files from standard input only.")
+ parser.add_argument('-s', '--summary', default=False, action="store_true", required=False, help="Display the score for each file.")
+ parser.add_argument('-a', '--average', default=False, action="store_true", required=False, help="Display the simple average of all scores.")
+ parser.add_argument('-t', '--total', default=False, action="store_true", required=False, help="Display the percentage of all compliant lines to the total number of lines in all files.")
+ parser.add_argument('-d', '--distribution', default="[95, 90]", action="store", required=False, type=str, help="a list containing the score distributions for pretty-printing. Default '[95, 90]' (green >= 95, yellow >= 90, red < 90).")
+ parser.add_argument('-o', '--output', default="text", action="store", required=False, type=str, help="the output format: 'text', 'csv', or 'gui'.")
+ parser.add_argument('-v', '--visual', default=False, action="store_true", required=False, help="Display a visual representation of the style check.")
+ parser.add_argument('-k', '--key', default="name", action="store", required=False, type=str, help="The sort key: Type '--key help' for the list.")
+ parser.add_argument('-e', '--exclude', default="", action="store", required=False, type=str, help="Exclude a comma separated set of one or more of: 'red', 'yellow', 'green'.")
+
+ parser.add_argument("files", help="Files to check", nargs="*")
+
+ args = parser.parse_args()
+
+ if args.summary == False and args.average == False and args.total == False and args.visual == False:
+ args.summary = True
+
+ targets = []
+
+ if args.stdin:
+ for line in sys.stdin:
+ t = line.strip()
+ if len(t) > 0:
+ targets.append(t)
+ else:
+ targets = args.files
+
+ UNCRUSTIFY = "@UNCRUSTIFY_BIN@"
+ UNCRUSTIFY_CONFIG = "@UNCRUSTIFY_CONFIG@"
+
+ StyleReport.commandLineMain(args, targets, UNCRUSTIFY, UNCRUSTIFY_CONFIG)
diff --git a/longbow/src/python/longbow-test-run.py b/longbow/src/python/longbow-test-run.py
new file mode 100755
index 00000000..77ed1f98
--- /dev/null
+++ b/longbow/src/python/longbow-test-run.py
@@ -0,0 +1,172 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+import os
+import sys
+import re
+import pprint
+import subprocess
+import argparse
+import json
+
+class TokenParser:
+ def __init__(self, tokens=[]):
+ self.index = 0
+ self.tokens = tokens
+
+ def nextToken(self):
+ result = self.tokens[self.index]
+ self.index = self.index + 1
+ return result
+
+ def previousToken(self):
+ self.index = self.index - 1
+ result = self.tokens[self.index - 1]
+ return result
+
+ def expectedToken(self, expected):
+ token = self.nextToken()
+ if token == expected:
+ return True
+ self.index = self.index - 1
+ print "expectedToken(%s) is not the actual %s" % (expected, token)
+ return False
+
+ def end(self):
+ if self.index == len(self.tokens):
+ return True
+ return False
+
+class LongBowCodeCoverage:
+ def __init__(self):
+ return
+
+ def run(self, executableFile):
+ lines = subprocess.check_output([ "gcov", "-f", executableFile ])
+ token = map(lambda x : x.strip("'"), re.split("[ :\n]+", lines))
+ return self.parse(token)
+
+ def parseFunction(self, parser):
+ functionName = parser.nextToken()
+ parser.expectedToken("Lines")
+ parser.expectedToken("executed")
+ coverage = parser.nextToken()
+ return { "function" : functionName, "coverage" : coverage }
+
+ def parseFile(self, parser):
+ fileName = parser.nextToken()
+ parser.expectedToken("Lines")
+ parser.expectedToken("executed")
+ coverage = parser.nextToken()
+ return { "file" : fileName, "coverage" : coverage }
+
+ def parse(self, tokens):
+ parser = TokenParser(tokens)
+ functions = [ ]
+
+ while not parser.end():
+ token = parser.nextToken()
+ if (token == "Function"):
+ function = self.parseFunction(parser)
+ functions.append(function)
+ elif (token == "File"):
+ file = self.parseFile(parser)
+ pass
+
+ self.detailCoverage = { "file" : file, "functions" : functions }
+ return self.detailCoverage
+
+ def getCoverage(self):
+ result["file"]["coverage"]
+
+ def getDetailCoverage(self):
+ return self.detailCoverage
+
+
+class LongBowTestRun:
+ def __init__(self, options=[]):
+ self.options = options
+ self.mainFileName = None
+ self.exitStatus = 0
+ return
+
+ def setOptions(self, options=[]):
+ self.options = options
+ return
+
+ def getMainFileName(self):
+ return self.mainFileName
+
+ def run(self, testRunner):
+ self.mainFileName = testRunner
+ self.exitStatus = 0
+
+ try:
+ try:
+ os.remove(testRunner + ".gcda")
+ except:
+ pass
+ lines = subprocess.check_output([ testRunner ])
+ lines = re.split("[ :]+", lines)
+ self.exitStatus = 0
+ except subprocess.CalledProcessError, e:
+ self.exitStatus = e.returncode
+
+ return self.exitStatus
+
+ def report(self, detailedOutput=False, jsonOutput=False):
+ result = ""
+ if self.exitStatus == 0:
+ coverage = LongBowCodeCoverage()
+ result = coverage.run(testRunner.getMainFileName())
+
+ if detailedOutput:
+ if jsonOutput:
+ result = json.dumps(result, sort_keys=False, indent=4, separators=(',', ': '))
+ else:
+ pp = str(result)
+ pass
+ else:
+ if jsonOutput:
+ result = json.dumps(result["file"], sort_keys=False, indent=4, separators=(',', ': '))
+ else:
+ result = "PASS " + result["file"]["file"] + " " + result["file"]["coverage"]
+ else:
+ result = "FAIL " + args.testRunner
+ pass
+
+ return result
+
+
+if __name__ == '__main__':
+ testRunners = []
+ if len(sys.argv) < 2:
+ print "Usage: longbow-test-run.py testExecutable"
+ print "Run a LongBow test"
+ sys.exit(1)
+
+ parser = argparse.ArgumentParser(description='Run a LongBow Test')
+ parser.add_argument("--json", help="Produce JSON output instead of a Python dictionary.", action="store_true")
+ parser.add_argument("--detailed", help="Produce detailed output.", action="store_true")
+ parser.add_argument("testRunner", help="The name of the test executable.", nargs='+')
+ args = parser.parse_args()
+
+ testRunner = LongBowTestRun([ "--run-nonforked" ])
+
+ for test in args.testRunner:
+ exitStatus = testRunner.run(test)
+ print testRunner.report(args.detailed, args.json)
+
diff --git a/longbow/src/python/longbow-test-suite.py b/longbow/src/python/longbow-test-suite.py
new file mode 100755
index 00000000..5a6d67e5
--- /dev/null
+++ b/longbow/src/python/longbow-test-suite.py
@@ -0,0 +1,55 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+import sys
+from subprocess import call
+
+class LongBowTestSuite:
+ def __init__(self):
+ self.options = []
+ return
+
+ def setOptions(self, options=[]):
+ self.options = options
+ return
+
+ def run(self, testRunners=[]):
+ result = 0
+ for test in testRunners:
+ outputFileName = test + ".log"
+ outputFile = open(outputFileName, 'w')
+ command = [ test ] + self.options
+ print command
+ status = call(command, stdout=outputFile)
+ if result == 0:
+ result = status
+ pass
+ outputFile.close()
+ pass
+ return result
+
+
+if __name__ == '__main__':
+ testRunners = []
+ if len(sys.argv) < 2:
+ print "Usage: longbow-test-suite.py testExecutable ..."
+ print "Run one or more LongBow test runners as indpendant processes"
+ sys.exit(1)
+ testRunners = testRunners + sys.argv[1:]
+
+ testSuite = LongBowTestSuite()
+ testSuite.setOptions([ "--run-nonforked" ])
+ exitStatus = testSuite.run(testRunners)
diff --git a/longbow/src/python/longbow-vocabulary-report.py b/longbow/src/python/longbow-vocabulary-report.py
new file mode 100755
index 00000000..25004428
--- /dev/null
+++ b/longbow/src/python/longbow-vocabulary-report.py
@@ -0,0 +1,66 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+
+import sys
+import argparse
+
+sys.path.append("@INSTALL_PYTHON_DIR@")
+sys.path.append("@DEPENDENCY_PYTHON_DIR@")
+sys.path.append("../site-packages/longbow/")
+import VocabularyReport
+import hfcca
+
+def main(argv):
+ desc = '''
+Print the vocabulary (number of tokens) of functions and files.
+
+The option --function displays the file name, function name,
+line number of the function, the number of tokens
+
+The default option --summary displays the file name, the average vocabulary
+of all functions in the file and a score ranging from 0 to 100.
+
+Usage:
+$ longbow-vocabulary-report parc_JSON.c
+parc_JSON.c 51.00 100.00
+$
+$ echo parc_JSON.c | longbow-vocabulary-report --function -o csv -
+vocabulary,parc_JSON.c,parcJSON_Create,49,50,100.00
+...
+$
+
+'''
+
+ parser = argparse.ArgumentParser(prog='longbow-vocabulary-report', formatter_class=argparse.RawDescriptionHelpFormatter, description=desc)
+ parser.add_argument('-s', '--summary', default=False, action="store_true", help="print the average vocabulary of each target file.")
+ parser.add_argument('-f', '--function', default=False, action="store_true", help="print the vocabulary of each function in each target file.")
+ parser.add_argument('-', '--stdin', default=False, action="store_true", required=False, help="read the list of files from standard input rather than the command line.")
+ parser.add_argument('-a', '--average', default=False, action="store_true", required=False, help="display only the simple average of the average vocabulary of each target file.")
+ parser.add_argument('-o', '--output', default="text", action="store", required=False, type=str, help="the output format: \"text\" or \"csv\"")
+ parser.add_argument("files", help="Files to check", nargs="*")
+
+ args = parser.parse_args()
+
+ VocabularyReport.commandLineMain(args, hfcca)
+
+
+if __name__ == "__main__":
+ '''
+@(#) longbow-vocabulary-report @VERSION@ @DATE@
+@(#) All Rights Reserved. Use is subject to license terms.
+ '''
+ main(sys.argv)
diff --git a/longbow/src/python/parc_uncrustify.cfg b/longbow/src/python/parc_uncrustify.cfg
new file mode 100755
index 00000000..475d8049
--- /dev/null
+++ b/longbow/src/python/parc_uncrustify.cfg
@@ -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.
+#
+
+
+indent_with_tabs = 0 # 1=indent to level only, 2=indent with tabs
+input_tab_size = 4 # original tab size
+output_tab_size = 4 # new tab size
+indent_columns = output_tab_size
+indent_label = 2 # pos: absolute col, neg: relative column
+# indent_align_string = False # align broken strings
+# indent_brace = 0
+
+nl_if_leave_one_liners = false # Don't split one-line if/else statements - 'if(a) b++;' (false/true)
+
+nl_enum_brace = remove # (ignore/add/remove/force) newline between 'enum' and '{'
+nl_union_brace = remove # "union {" vs "union \n {"
+nl_struct_brace = remove # "struct {" vs "struct \n {"
+nl_do_brace = remove # "do {" vs "do \n {"
+nl_if_brace = remove # "if () {" vs "if () \n {"
+nl_for_brace = remove # "for () {" vs "for () \n {"
+nl_else_brace = remove # "else {" vs "else \n {"
+nl_while_brace = remove # "while () {" vs "while () \n {"
+nl_switch_brace = remove # "switch () {" vs "switch () \n {"
+# nl_func_var_def_blk = 1
+# nl_before_case = 1
+nl_fcall_brace = add # "foo() {" vs "foo()\n{"
+nl_fdef_brace = add # "int foo() {" vs "int foo()\n{"
+# nl_after_return = TRUE
+nl_brace_while = remove
+nl_brace_else = remove
+nl_squeeze_ifdef = TRUE
+nl_func_type_name = add # (ignore/add/remove/force) newline between return type and function name in a function definition
+
+
+# The span for aligning struct initializer values (0=don't align)
+align_struct_init_span = 4 # number
+
+# Spaces to indent 'case' from 'switch'
+# Usually 0 or indent_columns.
+indent_switch_case = 4 # number
+
+# Make all if/elseif/else statements in a chain be braced or not. Overrides mod_full_brace_if.
+# If any must be braced, they are all braced. If all can be unbraced, then the braces are removed.
+mod_full_brace_if_chain = false # false/true
+# mod_paren_on_return = add # "return 1;" vs "return (1);"
+mod_full_brace_if = add # "if (a) a--;" vs "if (a) { a--; }"
+mod_full_brace_for = add # "for () a--;" vs "for () { a--; }"
+mod_full_brace_do = add # "do a--; while ();" vs "do { a--; } while ();"
+mod_full_brace_while = add # "while (a) a--;" vs "while (a) { a--; }"
+mod_remove_empty_return = true # Remove a void 'return;' that appears as the last statement in a function. (false/true)
+
+sp_after_ptr_star = remove # (ignore/add/remove/force) space after pointer star '*', if followed by a word.
+sp_func_proto_paren = remove # (ignore/add/remove/force) A space between function name and '(' on function declaration
+sp_return_paren = force # (ignore/add/remove/force) a space between 'return' and '('
+sp_before_semi = remove
+sp_paren_paren = remove # space between (( and ))
+sp_sizeof_paren = remove # "sizeof (int)" vs "sizeof(int)"
+sp_before_sparen = force # "if (" vs "if("
+sp_after_sparen = force # "if () {" vs "if (){"
+sp_after_cast = add # "(int) a" vs "(int)a"
+sp_inside_braces = force # "{ 1 }" vs "{1}"
+sp_inside_braces_struct = force # "{ 1 }" vs "{1}"
+sp_inside_braces_enum = force # "{ 1 }" vs "{1}"
+sp_inside_paren = remove # "( 1 )" vs "(1)"
+sp_inside_fparen = remove # "( 1 )" vs "(1)" - functions
+sp_inside_sparen = remove # "( 1 )" vs "(1)" - if/for/etc
+sp_type_func = add # ignore/add/remove/force A space between return type and function name
+sp_assign = force
+sp_arith = force
+sp_bool = force
+sp_compare = force
+sp_after_comma = force
+sp_func_def_paren = remove # "int foo (){" vs "int foo(){"
+sp_func_call_paren = remove # "foo (" vs "foo("
+sp_func_proto_paren = remove # "int foo ();" vs "int foo();"
+sp_paren_brace = add # Force a space between ')' and '{'
+sp_else_brace = add # Add or remove space between 'else' and '{' if on the same line (ignore/add/remove/force)
+sp_brace_else = force # Add or remove space between '}' and 'else' if on the same line (ignore/add/remove/force)
+
+# align_with_tabs = FALSE # use tabs to align
+# align_on_tabstop = FALSE # align on tabstops
+# align_enum_equ_span = 4
+# align_nl_cont = TRUE
+# align_var_def_span = 2
+# align_var_def_inline = TRUE
+# align_var_def_star = TRUE
+# align_var_def_colon = TRUE
+# align_assign_span = 1
+# align_struct_init_span = 3
+# align_var_struct_span = 3
+# align_right_cmt_span = 3
+# align_pp_define_span = 3
+# align_pp_define_gap = 4
+# align_number_left = TRUE
+# align_typedef_span = 5
+# align_typedef_gap = 3
+
+cmt_star_cont = TRUE # put a star on subsequent comment lines
+
+eat_blanks_before_close_brace = TRUE
+eat_blanks_after_open_brace = TRUE
+
+# Add or remove space between pointer stars '*'
+sp_between_ptr_star = remove
diff --git a/longbow/src/python/site-packages/CMakeLists.txt b/longbow/src/python/site-packages/CMakeLists.txt
new file mode 100644
index 00000000..f0be88f6
--- /dev/null
+++ b/longbow/src/python/site-packages/CMakeLists.txt
@@ -0,0 +1,12 @@
+install(FILES longbow.pth DESTINATION ${INSTALL_BASE_PYTHON_DIR} COMPONENT library)
+install(FILES longbow/LongBow.py DESTINATION ${INSTALL_PYTHON_DIR} COMPONENT library)
+install(FILES longbow/FileUtil.py DESTINATION ${INSTALL_PYTHON_DIR} COMPONENT library)
+install(FILES longbow/GCov.py DESTINATION ${INSTALL_PYTHON_DIR} COMPONENT library)
+install(FILES longbow/GCovSummary.py DESTINATION ${INSTALL_PYTHON_DIR} COMPONENT library)
+install(FILES longbow/ANSITerm.py DESTINATION ${INSTALL_PYTHON_DIR} COMPONENT library)
+install(FILES longbow/SymbolTable.py DESTINATION ${INSTALL_PYTHON_DIR} COMPONENT library)
+install(FILES longbow/Language_C.py DESTINATION ${INSTALL_PYTHON_DIR} COMPONENT library)
+install(FILES longbow/StyleReport.py DESTINATION ${INSTALL_PYTHON_DIR} COMPONENT library)
+install(FILES longbow/CoverageReport.py DESTINATION ${INSTALL_PYTHON_DIR} COMPONENT library)
+install(FILES longbow/VocabularyReport.py DESTINATION ${INSTALL_PYTHON_DIR} COMPONENT library)
+install(FILES longbow/NameReport.py DESTINATION ${INSTALL_PYTHON_DIR} COMPONENT library)
diff --git a/longbow/src/python/site-packages/longbow.pth b/longbow/src/python/site-packages/longbow.pth
new file mode 100755
index 00000000..9f0d4f64
--- /dev/null
+++ b/longbow/src/python/site-packages/longbow.pth
@@ -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.
+#
+
+#
+#
+# longbow package configuration
+longbow
diff --git a/longbow/src/python/site-packages/longbow/.gitignore b/longbow/src/python/site-packages/longbow/.gitignore
new file mode 100644
index 00000000..0d20b648
--- /dev/null
+++ b/longbow/src/python/site-packages/longbow/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/longbow/src/python/site-packages/longbow/ANSITerm.py b/longbow/src/python/site-packages/longbow/ANSITerm.py
new file mode 100755
index 00000000..8594c949
--- /dev/null
+++ b/longbow/src/python/site-packages/longbow/ANSITerm.py
@@ -0,0 +1,62 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+import os
+import subprocess
+import re
+import sys
+import pprint
+
+ansiRed = "\x1b[31m";
+ansiGreen = "\x1b[32m";
+ansiYellow = "\x1b[33m";
+ansiBlue = "\x1b[34m";
+ansiMagenta = "\x1b[35m";
+ansiCyan = "\x1b[36m";
+ansiReset = "\x1b[0m";
+
+def colorize(color, chars):
+
+ result = chars
+ if color == "red":
+ result = ansiRed + chars + ansiReset
+ elif color == "green":
+ result = ansiGreen + chars + ansiReset
+ elif color == "yellow":
+ result = ansiYellow + chars + ansiReset
+ elif color == "blue":
+ result = ansiBlue + chars + ansiReset
+ elif color == "magenta":
+ result = ansiMagenta + chars + ansiReset
+ elif color == "cyan":
+ result = ansiCyan + chars + ansiReset
+ else:
+ print >> sys.stderr, "Bad color name:", color
+
+ return result
+
+
+def printColorized(color, string):
+ print colorize(color, string)
+ return
+
+
+class ANSITerm:
+ def __init__(self):
+ return
+
+ def printColorized(self, color, string):
+ print colorize(color, string)
diff --git a/longbow/src/python/site-packages/longbow/CoverageReport.py b/longbow/src/python/site-packages/longbow/CoverageReport.py
new file mode 100755
index 00000000..c18ae056
--- /dev/null
+++ b/longbow/src/python/site-packages/longbow/CoverageReport.py
@@ -0,0 +1,262 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+import sys
+import os
+import re
+import subprocess
+import difflib
+import csv
+# import argparse
+import pprint
+# sys.path.append("${INSTALL_PYTHON_DIR}")
+# sys.path.append("${DEPENDENCY_PYTHON_DIR}")
+# sys.path.append("../site-packages/longbow/")
+import LongBow
+import GCov
+import GCovSummary
+import FileUtil
+import ANSITerm
+import Language_C
+
+def checkTestExecutable(executableFileName):
+ result = False
+
+ if not os.path.exists(executableFileName):
+ return result
+
+ path = os.path.dirname(executableFileName)
+ pattern = os.path.basename(executableFileName)+'*.gcda'
+ if not Language_C.findFiles(path, pattern):
+ return result
+
+ pattern = os.path.basename(executableFileName)+'*.gcno'
+ if not Language_C.findFiles(path, pattern):
+ return result
+
+ result = True
+ return result
+
+def findTestExecutable(fileName, hints=[]):
+ '''
+Given a file name, look in the canonical places for a corresponding LongBow test file.
+ '''
+ directoryName = os.path.dirname(fileName)
+ if len(directoryName) == 0:
+ directoryName = "."
+
+ file = Language_C.Module(fileName)
+
+ possibleTestFiles = list()
+ for hint in hints:
+ possibleTestFiles.append(hint + "/" + file.getExecutableName())
+ possibleTestFiles.append(hint + "/" + file.getTestExecutableName())
+ possibleTestFiles.append(directoryName + "/" + file.getExecutableName())
+ possibleTestFiles.append(directoryName + "/" + file.getTestExecutableName())
+ possibleTestFiles.append(directoryName + "/test/" + file.getTestExecutableName())
+
+ result = None
+ for possibleTestFile in possibleTestFiles:
+ if checkTestExecutable(possibleTestFile) == True:
+ result = os.path.abspath(possibleTestFile)
+ break
+
+ return result
+
+
+def textSummary(args, filesAndTests, gCovResults, prefix=""):
+
+ summary = GCov.computeSummary(filesAndTests, gCovResults)
+
+ if not args.includeTestSources:
+ summary = GCovSummary.removeTestSourceFiles(summary)
+
+ if len(summary) == 0:
+ return
+
+ if args.explain:
+ pp = pprint.PrettyPrinter(indent=2, width=150)
+ pp.pprint(summary)
+
+ maximumFileLength = max(map(lambda entry: len(entry), summary))
+
+ format = "%s%-" + str(maximumFileLength) + "s %6s"
+ print format % (prefix, "File Path", "Score")
+
+ format = "%s%-" + str(maximumFileLength) + "s %6.2f"
+ for testedFile in sorted(summary.keys()):
+ string = format % (prefix, testedFile, summary[testedFile]["coverage"])
+ if summary[testedFile]["direct"] == "indirect":
+ ANSITerm.printColorized("magenta", string)
+ else:
+ LongBow.scorePrinter(eval(args.distribution), summary[testedFile]["coverage"], string)
+
+ return
+
+
+def textAverage(args, filesAndTests, gcovResults):
+ summary = GCov.computeSummary(filesAndTests, gcovResults)
+
+ if not args.includeTestSources:
+ summary = GCovSummary.removeTestSourceFiles(summary)
+
+ score = GCovSummary.averageCoverage(summary)
+
+ LongBow.scorePrinter(eval(args.distribution), score, "%.2f" % (score))
+ return score
+
+
+def csvSummary(args, filesAndTests, gCovResults):
+ summary = GCov.computeSummary(filesAndTests, gCovResults)
+
+ if not args.includeTestSources:
+ summary = GCovSummary.removeTestSourceFiles(summary)
+
+ if len(summary) > 0:
+ for testedFile in sorted(summary.keys()):
+ outputString = "%s,%.2f" % (testedFile, summary[testedFile]["coverage"])
+ LongBow.scorePrinter(eval(args.distribution), summary[testedFile]["coverage"], outputString)
+
+ return
+
+
+def csvAverage(args, filesAndTests, gcovResults):
+ summary = GCov.computeSummary(filesAndTests, gcovResults)
+
+ if not args.includeTestSources:
+ summary = GCovSummary.removeTestSourceFiles(summary)
+
+ score = GCovSummary.averageCoverage(summary)
+
+ LongBow.scorePrinter(eval(args.distribution), score, "%.2f" % (score))
+ return
+
+
+def textVisualDisplayGcovLine(line):
+ token = line.split(":", 2)
+ if len(token) == 3:
+ if token[0] == "#####":
+ print ANSITerm.colorize("red", token[1] + " " + token[2])
+ elif token[0] == "$$$$$":
+ print ANSITerm.colorize("yellow", token[1] + " " + token[2])
+ else:
+ print ANSITerm.colorize("green", token[1] + " " + token[2])
+
+ return
+
+
+def textVisual(args, filesAndTests, gcovResults):
+
+ summary = GCov.computeSummary(filesAndTests, gcovResults)
+ if args.explain:
+ pp = pprint.PrettyPrinter(indent=2, width=150)
+ pp.pprint(summary)
+ pp.pprint(filesAndTests)
+
+ for entry in filesAndTests:
+ print entry[0]
+ try:
+ gcovLines = summary[entry[0]]["gcovLines"]
+ map(lambda line: textVisualDisplayGcovLine(line.strip()), gcovLines)
+ except KeyError:
+ print >> sys.stderr, "No coverage information for", entry[0]
+
+ return
+
+
+def displaySummary(args, filesAndTests, newGCovResults):
+ if args.output == "text":
+ textSummary(args, filesAndTests, newGCovResults)
+ elif args.output == "csv":
+ csvSummary(args, filesAndTests, newGCovResults)
+ else:
+ print >> sys.stderr, "Unsupported output type"
+ return
+
+
+def displayAverage(args, filesAndTests, gcovResults):
+ if args.output == "text":
+ textAverage(args, filesAndTests, gcovResults)
+ elif args.output == "csv":
+ csvAverage(args, filesAndTests, gcovResults)
+ else:
+ print >> sys.stderr, "Unsupported output type"
+ return
+
+
+def explain(args, filesAndTests, gcovResults):
+
+ pp = pprint.PrettyPrinter(indent=2, width=150)
+ pp.pprint(gcovResults)
+
+ return
+
+def getFilesAndTests(fileNames, testDirs=[]):
+ namesAndPaths = map(lambda fileName: [fileName, os.path.abspath(fileName)], fileNames)
+ filesAndTests = map(lambda nameAndPath: [ nameAndPath[0], findTestExecutable(nameAndPath[1], testDirs) ], namesAndPaths)
+ return filesAndTests
+
+
+def gradeAndPrint(targets, testDirs=[], problemsOnly=False, prefix=""):
+ filesAndTests = getFilesAndTests(targets, testDirs)
+ newGCovResults = map(lambda fileAndTestFile: GCov.getCoverage(fileAndTestFile[1]), filesAndTests)
+
+ summarys = GCov.computeSummary(filesAndTests, newGCovResults)
+ if len(summarys) < 1:
+ print "%sNo GCov Results - Please be sure to run 'make check' first" % prefix
+ return False
+ summarys = GCovSummary.removeTestSourceFiles(summarys)
+
+ paths = summarys.keys()
+ if problemsOnly:
+ paths = filter(lambda key: summarys[key]["coverage"] < 100, paths)
+
+ distribution=[99,90]
+ maximumFileLength = max(map(lambda entry: len(os.path.relpath(entry)), paths))
+ format = "%s%-" + str(maximumFileLength) + "s %6s"
+ print format % (prefix, "File Path", "Score")
+ format = "%s%-" + str(maximumFileLength) + "s %6.2f"
+ for path in sorted(paths):
+ string = format % (prefix, os.path.relpath(path), summarys[path]["coverage"])
+ LongBow.scorePrinter(distribution, summarys[path]["coverage"], string)
+
+ return True
+
+def commandLineMain(args, fileNames, testDir=""):
+
+ testDirs = []
+ if testDir:
+ testDirs.append(testDir)
+ fileNames = map(lambda fileName: os.path.abspath(fileName), fileNames)
+ filesAndTests = map(lambda fileName: [fileName, findTestExecutable(fileName, testDirs)], fileNames)
+
+ filesWithNoTest = filter(lambda fileAndTest: fileAndTest[1] == None, filesAndTests)
+ if len(filesWithNoTest) != 0:
+ outputFormat = "%s has no corresponding test executable or coverage data.\n"
+ map(lambda filesAndTests: sys.stderr.write(outputFormat % (filesAndTests[0])), filesWithNoTest)
+
+ gCovResults = map(lambda fileAndTestFile: GCov.getCoverage(fileAndTestFile[1]), filesAndTests)
+
+ if args.summary is True:
+ displaySummary(args, filesAndTests, gCovResults)
+ elif args.average is True:
+ displayAverage(args, filesAndTests, gCovResults)
+ elif args.visual is True:
+ textVisual(args, filesAndTests, gCovResults)
+ elif args.explain is True:
+ explain(args, filesAndTests, gCovResults)
+
+ return True
diff --git a/longbow/src/python/site-packages/longbow/DoxygenReport.py b/longbow/src/python/site-packages/longbow/DoxygenReport.py
new file mode 100755
index 00000000..46edf047
--- /dev/null
+++ b/longbow/src/python/site-packages/longbow/DoxygenReport.py
@@ -0,0 +1,161 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+
+import sys
+import os
+import pprint
+import subprocess
+import difflib
+import csv
+import LongBow
+
+def concatenateContinuationLines(lines):
+ '''
+ Parse doxygen log lines.
+ Lines that are indented by a space are continutations of the previous line.
+ '''
+ result = list()
+ accumulator = ""
+ for line in lines:
+ line = line.rstrip()
+ if line.startswith(" ") == False and line.startswith(" ") == False:
+ if len(accumulator) > 0:
+ result.append(accumulator)
+ accumulator = line
+ else:
+ accumulator = accumulator + " " + line.lstrip()
+
+ result.append(accumulator)
+
+ return result
+
+def parseLine(line):
+ result = None
+ if not line.startswith("<"):
+ fields = line.split(":")
+ if len(fields) >= 4:
+ result = { "fileName" : fields[0].strip(),
+ "lineNumber" : int(fields[1].strip()),
+ "type" : "documentation",
+ "severity" : fields[2].strip(),
+ "message" : " ".join(fields[3:]).strip()}
+ elif line.startswith("error"):
+ print line
+ elif len(line) > 0:
+ print "Consider using doxygen -s:", line
+
+ return result
+
+def canonicalize(lines):
+ lines = concatenateContinuationLines(lines)
+ parsedLines = map(lambda line: parseLine(line), lines)
+ parsedLines = filter(lambda line: line != None, parsedLines)
+ return parsedLines
+
+def organize(entries):
+ result = dict()
+
+ for entry in entries:
+ if not entry["fileName"] in result:
+ result[entry["fileName"]] = dict()
+
+ entryByFile = result[entry["fileName"]]
+
+ if not str(entry["lineNumber"]) in entryByFile:
+ entryByFile[str(entry["lineNumber"])] = list()
+ if not entry in entryByFile[str(entry["lineNumber"])]:
+ entryByFile[str(entry["lineNumber"])].append(entry)
+
+ return result
+
+def textualSummary(distribution, documentation):
+ maxWidth = 0
+ for entry in documentation:
+ if len(entry) > maxWidth:
+ maxWidth = len(entry)
+
+ formatString ="%-" + str(maxWidth) + "s %8d %8d %.2f%%"
+ for entry in documentation:
+ badLines = len(documentation[entry])
+ totalLines = LongBow.countLines(entry)
+ score = float(totalLines - badLines) / float(totalLines) * 100.0
+ LongBow.scorePrinter(distribution, score, formatString % (entry, totalLines, badLines, score))
+ return
+
+def textualAverage(distribution, documentation, format):
+ sum = 0.0
+
+ for entry in documentation:
+ badLines = len(documentation[entry])
+ totalLines = LongBow.countLines(entry)
+ score = float(totalLines - badLines) / float(totalLines) * 100.0
+ sum = sum + score
+
+ if len(documentation) == 0:
+ averageScore = 100.0
+ else:
+ averageScore = sum / float(len(documentation))
+
+ LongBow.scorePrinter(distribution, averageScore, format % averageScore)
+
+def csvSummary(distribution, documentation):
+ formatString ="documentation,%s,%d,%d,%.2f%%"
+ for entry in documentation:
+ badLines = len(documentation[entry])
+ totalLines = LongBow.countLines(entry)
+ score = float(totalLines - badLines) / float(totalLines) * 100.0
+ LongBow.scorePrinter(distribution, score, formatString % (entry, totalLines, badLines, score))
+ return
+
+
+def gradeAndPrint(targets, doxLogfile, problemsOnly=False, prefix=""):
+ with open(doxLogfile, 'r') as f:
+ lines = f.readlines()
+
+ lines = canonicalize(lines)
+
+ result = organize(lines)
+
+ pp = pprint.PretyPrinter(intent=len(prefix))
+
+ distribution=[100, 95]
+ textualSummary(distribution, result)
+ return True
+
+def commandLineMain(args, fileNames):
+ if not args.summary and not args.average:
+ args.summary = True
+
+ with open(args.doxygenlog, 'r') as f:
+ lines = f.readlines()
+
+ lines = canonicalize(lines)
+
+ result = organize(lines)
+
+ pp = pprint.PrettyPrinter(indent=4)
+ #pp.pprint(result)
+
+ distribution = eval(args.distribution)
+ if args.summary:
+ if args.output == "text":
+ textualSummary(distribution, result)
+ else:
+ csvSummary(distribution, result)
+
+ if args.average:
+ textualAverage(distribution, result, "%.2f")
diff --git a/longbow/src/python/site-packages/longbow/FileUtil.py b/longbow/src/python/site-packages/longbow/FileUtil.py
new file mode 100755
index 00000000..ae3113f6
--- /dev/null
+++ b/longbow/src/python/site-packages/longbow/FileUtil.py
@@ -0,0 +1,102 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+
+import sys
+import os
+import csv
+import subprocess
+
+def readFileLines(fileName):
+ '''
+ Get the entire file into memory as a list of lines.
+ '''
+ result = None
+
+ with open(fileName, "r") as file:
+ result = file.readlines()
+
+ return result
+
+def readFileString(fileName):
+ '''
+ Get the entire file into memory as a python string.
+ '''
+ result = None
+
+ if fileName != None and len(fileName) > 0:
+ with open (fileName, "r") as file:
+ result = file.read()
+
+ return result
+
+def sourceFileNameToName(sourceFileName):
+ '''
+ Given the path to a source file, return the name without any path components or trailing suffix.
+ '''
+ name = os.path.basename(sourceFileName)
+ return name.split(".")[0]
+
+def canonicalizeFunctionName(functionName):
+ '''
+ Given a function name that contains the initial '_' character,
+ strip it and return a canonicalised form of the same name suitable for a source file.
+ '''
+ if functionName[0] == "_":
+ functionName = functionName[1:]
+ return functionName
+
+def isReservedName(functionName):
+ '''
+ Given a canonicalized name, determine if it is a reserved name according to ISO/IEC 9899:2011 and ANSI Sec. 4.1.2.1,
+ identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
+ '''
+ if functionName[0] == '_' and functionName[1] == '_':
+ return True
+ elif functionName[0] == '_' and functionName[1].isupper():
+ return True
+ return False
+
+def getDarwinTestableFunctions(objectFileName):
+ '''
+ Retrieve a set of local and global function names within a file.
+ '''
+ command = [ "/usr/bin/nm", "-gUm", objectFileName ]
+
+ output = subprocess.check_output(command)
+ lines = output.splitlines()
+
+ external = []
+ internal = []
+ for line in lines:
+ if line:
+ fields = line.split(" ")
+ if (len(fields) > 1) and (fields[1] == "(__TEXT,__text)"):
+ functionName = canonicalizeFunctionName(fields[3])
+
+ if not isReservedName(functionName):
+ if fields[2] == "external":
+ external.append( ( functionName ) )
+ else:
+ internal.append( ( functionName ) )
+ pass
+ pass
+ pass
+ pass
+
+ external.sort()
+ internal.sort()
+ return { "Local": internal, "Global" : external }
diff --git a/longbow/src/python/site-packages/longbow/GCov.py b/longbow/src/python/site-packages/longbow/GCov.py
new file mode 100755
index 00000000..c2705fda
--- /dev/null
+++ b/longbow/src/python/site-packages/longbow/GCov.py
@@ -0,0 +1,232 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+import os
+import subprocess
+import re
+import sys
+import pprint
+import FileUtil
+import Language_C
+
+class GCov:
+ def __init__(self):
+ return
+
+def canonicalizeLines(lines):
+ result = []
+ accumulatedLine = ""
+ for line in lines:
+ line = line.strip()
+ if len(line) == 0:
+ if len(accumulatedLine.strip()) > 0:
+ result.append(accumulatedLine.strip())
+ accumulatedLine = ""
+ elif "creating" in line:
+ if len(accumulatedLine.strip()) > 0:
+ result.append(accumulatedLine.strip())
+ accumulatedLine = ""
+ result.append(line)
+ else:
+ accumulatedLine = accumulatedLine + " " + line
+ return result
+
+def executeGCovCommand(testExecutableFileName):
+ currentDirectory = os.getcwd()
+ targetDirectory = os.path.dirname(os.path.abspath(testExecutableFileName))
+ testExecutableBaseName = os.path.basename(testExecutableFileName)
+
+ os.chdir(targetDirectory)
+ objects = Language_C.findFiles("./", testExecutableBaseName+"*.o")
+ if not objects:
+ return
+ objdir = os.path.dirname(objects[0])
+ gcdas = Language_C.findFiles("./", testExecutableBaseName+"*.gcda")
+ if not gcdas:
+ return
+ gcda = gcdas[0]
+ gcnos = Language_C.findFiles("./", testExecutableBaseName+"*.gcno")
+ if not gcnos:
+ return
+ gcno = gcnos[0]
+ proc = subprocess.Popen(['gcov', '-af', '-o='+objdir, '-gcda='+gcda, '-gcno='+gcno, testExecutableBaseName], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ os.chdir(currentDirectory)
+
+ inputLines = map(lambda line: line.strip(), proc.stdout)
+
+ return canonicalizeLines(inputLines)
+
+def parseFunctionLine(line):
+ # Function 'TestFixture_Global_TearDown' Lines executed:71.43% of 7"
+ search = re.search("Function '(.*)' Lines executed:(.*)% of (.*)", line, re.IGNORECASE)
+
+ result = []
+ if search:
+ functionName = search.group(1)
+ percentage = search.group(2)
+ totalLines = search.group(3)
+ result = { functionName : { "coverage" : float(percentage), "numberOfLines" : int(totalLines) } }
+
+ return result
+
+def parseFileLine(testExecutableDirectoryName, line):
+ # File './../parc_Buffer.c' Lines executed:92.69% of 424
+ search = re.search("File '(.*)' Lines executed:(.*)% of (.*)", line, re.IGNORECASE)
+
+ result = { }
+ if search:
+ baseName = os.path.basename(search.group(1));
+ fileName = os.path.abspath(testExecutableDirectoryName + "/" + baseName)
+ percentage = search.group(2)
+ totalLines = search.group(3)
+ result = { fileName : { "coverage" : float(percentage), "totalLines" : int(totalLines) } }
+
+ return result
+
+def parseCreatingLine(testExecutableDirectoryName, line):
+ search = re.search("(.*):creating '(.*)'", line, re.IGNORECASE)
+
+ result = None
+ if search:
+ baseName = os.path.basename(search.group(1));
+ fileName = os.path.abspath(testExecutableDirectoryName + "/" + baseName)
+ baseName = os.path.basename(search.group(2));
+ gcovFileName = os.path.abspath(testExecutableDirectoryName + "/" + baseName)
+
+ result = { "fileName" : fileName, "gcovFileName" : gcovFileName, "gcovLines" : FileUtil.readFileLines(gcovFileName) }
+
+ return result
+
+
+def computeCoverageFromGCovLines(testExecutableDirectoryName, testExecutableFileName, lines):
+ '''
+ This produces a dictionary consisting of:
+
+ 'testedFiles' : dictionary containing as keys 'functions' and the name of a file that was tested
+
+ The value of the key that is the name of a file that was tested is a dictionary containing the keys,
+ 'coverage', 'gcovFileName', and 'gcovLines'
+
+ 'coverage' is the percentage of code executed
+
+ 'testedFunctions' is a list containing lists consisting of the function name, the percent executed, and the number of lines in the function.
+ '''
+ testedFiles = { }
+ testedFunctions = { }
+ gcovFileNames = []
+ for line in lines:
+ if line.startswith("Function"):
+ element = parseFunctionLine(line)
+ testedFunctions.update(element)
+ elif line.startswith("File"):
+ element = parseFileLine(testExecutableDirectoryName, line)
+ testedFiles.update(element)
+ else:
+ element = parseCreatingLine(testExecutableDirectoryName, line)
+ if element != None:
+ fileName = element["fileName"]
+ del element["fileName"]
+ testedFiles[fileName].update(element)
+ pass
+
+ result = { testExecutableFileName : { "testedFunctions" : testedFunctions, "testedFiles" : testedFiles } }
+
+ return result
+
+
+def noCoverage():
+ result = { "testedFiles" : { }, "testedFunctions" : { } }
+ return result
+
+def getCoverage(testExecutableFileName):
+ '''
+ '''
+ if testExecutableFileName == None:
+ return None
+
+ testExecutableFileName = os.path.abspath(testExecutableFileName)
+ testExecutableDirectoryName = os.path.dirname(testExecutableFileName)
+ gcovLines = executeGCovCommand(testExecutableFileName)
+
+ return computeCoverageFromGCovLines(testExecutableDirectoryName, testExecutableFileName, gcovLines)
+
+
+def selectGreaterCoverage(testedFileA, testedFileB):
+ result = testedFileB
+ if testedFileA["coverage"] >= testedFileB["coverage"]:
+ result = testedFileA
+
+ return result
+
+def computeSummary(filesAndTests, newGCovResults):
+ '''
+ First, for each target file named in the gcov results, find the corresponding testedFile and report the maximum coverage.
+
+ If the target file is not in any of the testedFiles
+
+ { targetFileName : { "coverage": percent, "veracity" : "direct" / "indirect" } }
+ '''
+
+ newGCovResults = filter(lambda entry: entry != None, newGCovResults)
+
+ result = dict()
+ for entry in newGCovResults:
+ for testExecutableName in entry:
+ testExecutableCSourceName = Language_C.Module(testExecutableName).getCSourceName()
+
+ for testedFileName in entry[testExecutableName]["testedFiles"]:
+ testedFile = entry[testExecutableName]["testedFiles"][testedFileName]
+
+ if Language_C.Module(testedFileName).getTestExecutableName() == os.path.basename(testExecutableName):
+ result[testedFileName] = testedFile
+ result[testedFileName]["direct"] = "direct"
+ elif testedFileName in result:
+ bestCoverage = selectGreaterCoverage(testedFile, result[testedFileName])
+ if result[testedFileName] != bestCoverage:
+ result[testedFileName] = bestCoverage
+ result[testedFileName]["direct"] = "indirect"
+ else:
+ result[testedFileName] = testedFile
+ result[testedFileName]["direct"] = "indirect"
+
+ return result
+
+def computeAverage(filesAndTests, gcovResults):
+ summary = computeSuperSummary(filesAndTests, gcovResults)
+
+ filesToAverage = removeTestSourceFiles(summary)
+
+ score = 0.0
+
+ if len(filesToAverage) > 0:
+ sum = reduce(lambda x, y: x + y, map(lambda entry: summary[entry]["coverage"], filesToAverage))
+ score = sum / float(len(filesToAverage))
+
+ return score
+
+
+if __name__ == '__main__':
+ pp = pprint.PrettyPrinter(indent=4, width=132)
+ if True:
+ gcovResult = getCoverage("/Users/gscott/Documents/workspace/Distillery/Libparc/parc/algol/test/test_parc_JSON")
+ else:
+ lines = sys.stdin.readlines()
+ lines = canonicalizeLines(lines)
+ pp.pprint(lines)
+
+ gcovResult = computeCoverageFromGCovLines("/Users/gscott/Documents/workspace/Distillery/Libparc/parc/algol/test/", lines)
+
+ pp.pprint(gcovResult)
diff --git a/longbow/src/python/site-packages/longbow/GCovSummary.py b/longbow/src/python/site-packages/longbow/GCovSummary.py
new file mode 100755
index 00000000..bfa6710a
--- /dev/null
+++ b/longbow/src/python/site-packages/longbow/GCovSummary.py
@@ -0,0 +1,42 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+import os
+import subprocess
+import re
+import sys
+import pprint
+import FileUtil
+import Language_C
+
+
+def removeTestSourceFiles(gcovSummary):
+ deleteThese = filter(lambda entry: Language_C.Module(entry).isTestSourceName(), gcovSummary)
+
+ for entry in deleteThese:
+ del gcovSummary[entry]
+
+ return gcovSummary
+
+
+def averageCoverage(summary):
+ score = 0.0
+
+ if len(summary) > 0:
+ sum = reduce(lambda x, y: x + y, map(lambda entry: summary[entry]["coverage"], summary))
+ score = sum / float(len(summary))
+
+ return score
diff --git a/longbow/src/python/site-packages/longbow/Language_C.py b/longbow/src/python/site-packages/longbow/Language_C.py
new file mode 100755
index 00000000..1d97a676
--- /dev/null
+++ b/longbow/src/python/site-packages/longbow/Language_C.py
@@ -0,0 +1,204 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+import os
+import glob
+
+import fnmatch
+import subprocess
+
+def findFiles(startDir, pattern):
+ matches = []
+ for root, dirnames, filenames in os.walk(startDir):
+ for filename in fnmatch.filter(filenames, pattern):
+ matches.append(os.path.join(root, filename))
+
+ return matches
+
+def getLibPathForObject(libraryPath, filename):
+ '''
+ Returns a path to an object file suitable for nm
+ '''
+ result = ''
+
+ command = ['/usr/bin/ar', '-t', libraryPath]
+ output = subprocess.check_output(command)
+ lines = output.splitlines()
+
+ for line in lines:
+ tokens = line.split('.')
+ if tokens[0] == filename:
+ result = libraryPath + '(' + line + ')'
+ break
+
+ return result
+
+class Module:
+ '''
+ Represent a C language module.
+ A module consists of the file names of the C source, C header file, object file, and an executable file
+ '''
+ def __init__(self, srcPath, objectDirs=[]):
+ self.path = self.initialzePath(srcPath)
+ if not objectDirs:
+ objectDirs = [self.path]
+ split = srcPath.split("/")
+ self.originalName = split[len(split) - 1]
+ self.originalBaseName = os.path.basename(srcPath)
+ tokens = self.originalBaseName.split('.')
+ self.fileName = tokens[0].replace("/","")
+
+ if self.fileName.startswith("test_"):
+ self.fileName = self.fileName[5:]
+
+ # Search for an appropriate object
+ self.objectPath = "";
+ for objectDir in objectDirs:
+ if objectDir.endswith(".a"):
+ self.objectPath = getLibPathForObject(objectDir, self.fileName)
+ if self.objectPath:
+ break
+ else:
+ objectSearchPath = os.path.join(objectDir, self.fileName) + "*.o*"
+ ofiles = glob.glob(objectSearchPath);
+ if ofiles:
+ # if we've found some matches, assume we want the first.
+ self.objectPath = ofiles[0];
+ break
+ return
+
+ def isTestExecutableName(self):
+ return self.getTestExecutableName() == self.originalBaseName
+
+ def isTestSourceName(self):
+ return self.getTestSourceName() == self.originalBaseName
+
+ def isCSourceName(self):
+ return self.getCSourceName() == self.originalBaseName
+
+ def isCHeaderName(self):
+ return self.getCHeaderName() == self.originalBaseName
+
+ def getCSourceName(self):
+ return self.fileName + ".c"
+
+ def getCHeaderName(self):
+ return self.fileName + ".h"
+
+ def getPathToObjectFile(self):
+ return self.objectPath;
+
+ def getExecutableName(self):
+ return self.fileName
+
+ def getTestExecutableName(self):
+ return "test_" + self.fileName
+
+ def getTestSourceName(self):
+ return self.getTestExecutableName() + ".c"
+
+ def getNamespace(self):
+ sourceFileName = self.getCSourceName()
+ if (sourceFileName.find("_") >= 0):
+ stripped = sourceFileName[0:sourceFileName.index("_")]
+ return stripped
+ else:
+ return None
+
+ def getModuleName(self):
+ sourceFileName = self.getCSourceName()
+ split = sourceFileName.split("/")
+ sourceFileName = split[len(split) - 1]
+ if (sourceFileName.find(".") >= 0):
+ stripped = sourceFileName[0:sourceFileName.index(".")]
+ return stripped
+ else:
+ return None
+
+ def getModulePrefix(self):
+ sourceFileName = self.getCSourceName()
+ squashed = sourceFileName.replace("_", "")
+ if (squashed.find(".") >= 0):
+ return squashed[0:squashed.index(".")]
+ else:
+ return None
+
+ def getTypeName(self):
+ sourceFileName = self.getCSourceName()
+ if (sourceFileName.find(".") >= 0 and sourceFileName.find("_") >= 0):
+ stripped = sourceFileName[(sourceFileName.index("_") + 1):sourceFileName.index(".")]
+ return stripped
+ else:
+ return None
+
+ def getModulePath(self):
+ return self.path
+
+ def initialzePath(self, sourceFileName):
+ parts = sourceFileName.split("/")
+ parts = parts[0:len(parts) - 1]
+ return '/'.join(map(str, parts))
+
+if __name__ == '__main__':
+ cFile = Module("file.c.gcov")
+ if cFile.getCSourceName() != "file.c":
+ print "getCSourceName failed", cFile.getCSourceName()
+
+ if cFile.getCHeaderName() != "file.h":
+ print "getCHeaderName failed", cFile.getCHeaderName()
+
+ if cFile.getTestSourceName() != "test_file.c":
+ print "getTestSourceName failed", cFile.getTestSourceName()
+
+ if cFile.getTestExecutableName() != "test_file":
+ print "getTestExecutableName failed", cFile.getTestExecutableName()
+
+ if cFile.getNamespace() != None:
+ print "getNamespace failed", cFile.getNamespace()
+
+ if cFile.getModuleName() != "file":
+ print "getModuleName failed", cFile.getModuleName()
+
+ if cFile.getModulePrefix() != "file":
+ print "getModulePrefix failed", cFile.getModulePrefix()
+
+ if cFile.getTypeName() != None:
+ print "getTypeName failed", cFile.getTypeName()
+
+ cFile = Module("parc_Object.c.gcov")
+ if cFile.getCSourceName() != "parc_Object.c":
+ print "getCSourceName failed", cFile.getCSourceName()
+
+ if cFile.getCHeaderName() != "parc_Object.h":
+ print "getCHeaderName failed", cFile.getCHeaderName()
+
+ if cFile.getTestSourceName() != "test_parc_Object.c":
+ print "getTestSourceName failed", cFile.getTestSourceName()
+
+ if cFile.getTestExecutableName() != "test_parc_Object":
+ print "getTestExecutableName failed", cFile.getTestExecutableName()
+
+ if cFile.getNamespace() != "parc":
+ print "getNamespace failed", cFile.getNamespace()
+
+ if cFile.getModuleName() != "parc_Object":
+ print "getModuleName failed", cFile.getModuleName()
+
+ if cFile.getModulePrefix() != "parcObject":
+ print "getModulePrefix failed", cFile.getModulePrefix()
+
+ if cFile.getTypeName() != "Object":
+ print "getTypeName failed", cFile.getTypeName()
diff --git a/longbow/src/python/site-packages/longbow/LongBow.py b/longbow/src/python/site-packages/longbow/LongBow.py
new file mode 100755
index 00000000..d1f0e77a
--- /dev/null
+++ b/longbow/src/python/site-packages/longbow/LongBow.py
@@ -0,0 +1,96 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+import sys
+
+ansiRed = "\x1b[31m";
+ansiGreen = "\x1b[32m";
+ansiYellow = "\x1b[33m";
+ansiMagenta = "\x1b[35m";
+ansiReset = "\x1b[0m";
+
+
+def buildRed(string):
+ if sys.stdout.isatty():
+ return ansiRed + string + ansiReset
+ else:
+ return string
+
+
+def buildGreen(string):
+ if sys.stdout.isatty():
+ return ansiGreen + string + ansiReset
+ else:
+ return string
+
+
+def buildYellow(string):
+ if sys.stdout.isatty():
+ return ansiYellow + string + ansiReset
+ else:
+ return string
+
+
+def score(distribution, score):
+ result = "red"
+
+ if (score > distribution[0]):
+ result = "green"
+ elif (score > distribution[1]):
+ result = "yellow"
+
+ return result
+
+
+def scoreBuilder(distribution, score, string):
+ '''
+ scores is a list of 2 decreasing values.
+ The first is the minimum score for green, the second is the minimum score for yellow.
+ The rest art red
+ '''
+ if (score > distribution[0]):
+ return buildGreen(string)
+ elif (score > distribution[1]):
+ return buildYellow(string)
+ else:
+ return buildRed(string)
+
+
+def scorePrinter(distribution, score, string):
+ print scoreBuilder(distribution, score, string)
+
+
+def countLines(fileName):
+ i = 0
+ with open(fileName) as f:
+ for i, l in enumerate(f):
+ pass
+ return i + 1
+
+
+def CFileNameToFunctionPrefix(fileName):
+ '''
+ Given the name of a C source file or header file,
+ return the canonical name prefix for functions within that file.
+ For example, the input name "parc_Buffer.c" results in "parcBuffer_"
+ '''
+ fileName = os.path.basename(fileName);
+ fileNameSpace = os.path.splitext(fileName)[0]
+ parts = fileNameSpace.partition("_")
+ result = None
+ if len(parts) == 3:
+ result = parts[0] + parts[2] + "_"
+ return result
diff --git a/longbow/src/python/site-packages/longbow/NameReport.py b/longbow/src/python/site-packages/longbow/NameReport.py
new file mode 100755
index 00000000..1d38b4ec
--- /dev/null
+++ b/longbow/src/python/site-packages/longbow/NameReport.py
@@ -0,0 +1,818 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+
+import sys
+import os
+import subprocess
+import argparse
+import csv
+import traceback
+
+import LongBow
+from Language_C import Module
+from FileUtil import *
+from pprint import pprint
+
+class NoObjectFileException(Exception):
+ def __init__(self, value):
+ self.value = value
+ def __str__(self):
+ return repr(self.value)
+
+
+# Global error string formatting map
+conformanceErrorFormatMap = {
+ "NAMESPACE_MISMATCH" : "Function signature %s does not have the correct namespace prefix (%s)",
+ "MODULE_MISMATCH" : "Function signature %s does not have the correct module prefix (%s)",
+ "INVALID_STATIC_NAME" : "Local function signature %s must begin with an underscore '_'.",
+ "INVALID_GLOBAL_ENUM_NAME" : "Global enumeration prefix %s must match the module namespace %s.",
+ "INVALID_STATIC_ENUM_NAME" : "Local enumeration prefix %s must begin with an underscore '_'.",
+ "INVALID_GLOBAL_ENUM_VALUE_NAME" : "Global enumeration value prefix %s must match the enum name %s.",
+ "INVALID_GLOBAL_TYPEDEF_NAME" : "Global typedef prefix %s must match the module namespace %s.",
+ "INVALID_STATIC_TYPEDEF_NAME" : "Local typedef prefix %s must begin with an underscore '_'.",
+}
+
+def tuplesListToCSV(points):
+ '''
+ Convert a list of tuples -- data points -- to a list of CSV-formatted strings.
+ '''
+ lines = []
+ for point in points:
+ line = ""
+ for i in range(len(point) - 1):
+ line = line + str(point[i]) + ","
+ line = line + str(point[-1])
+ lines.append(line)
+ return lines
+
+def tuplesListToPrettyText(points, distribution = [99, 90]):
+ '''
+ Convert a list of tuples -- data points -- to a list of colorized strings based
+ on the provided distribution.
+ '''
+ lines = []
+ for point in points:
+ line = ""
+ for i in range(len(point) - 1):
+ line = line + str(point[i]) + " "
+ line = line + str(point[-1])
+ lines.append(LongBow.scoreBuilder(distribution, point[-1], line))
+ return lines
+
+def writeListToStream(llist, fileHandle, appendNewLine = True):
+ '''
+ Write the list of lines to the given file stream handle, appending a new line after
+ every line if told to do so.
+ '''
+ for line in llist:
+ fileHandle.write(line)
+ if appendNewLine:
+ fileHandle.write("\n")
+
+def isValidModuleName(namespace, typeName, moduleName):
+ '''
+ Determine if a given module name is valid (conforming) given the namespace and typename.
+
+ For example, a module in the `parc` namespace with typename `JSON` must be named `parc_JSON`.
+ '''
+ constructedName = namespace + "_" + typeName
+ return (moduleName == constructedName)
+
+def isValidFunctionName(namespace, modulePrefix, functionName, scope):
+ '''
+ Determine if a given function name is valid (conforming) given the namespace and typename.
+ '''
+ if (scope != "Local"):
+ if(not functionName.startswith(namespace)):
+ return False, conformanceErrorFormatMap["NAMESPACE_MISMATCH"] % ('"' + functionName + '"', namespace)
+ elif (not functionName.startswith(modulePrefix)):
+ return False, conformanceErrorFormatMap["MODULE_MISMATCH"] % ('"' + functionName + '"', modulePrefix)
+ else:
+ return True, ""
+ elif (scope == "Local" and not functionName.startswith("_")):
+ return False, conformanceErrorFormatMap["INVALID_STATIC_NAME"] % ('"' + functionName + '"')
+ else:
+ return True, ""
+
+def isValidTypedefName(typePrefix, name, static):
+ '''
+ Determine if a given typedef name is valid (conforming) given the namespace and typename.
+ '''
+ originalName = name
+ originalTypePrefix = typePrefix
+
+ name = name.lower()
+ typePrefix = typePrefix.lower()
+
+ if ((not static) and name.startswith(typePrefix)) and originalName[0].isupper():
+ return True, ""
+ elif ((not static) and (not name.startswith(typePrefix))):
+ return False, conformanceErrorFormatMap["INVALID_GLOBAL_TYPEDEF_NAME"] % ('"' + originalName + '"', originalTypePrefix)
+ elif (static and name.startswith('_')):
+ return True, ""
+ else:
+ return False, conformanceErrorFormatMap["INVALID_STATIC_TYPEDEF_NAME"] % ('"' + originalName + '"')
+
+def isValidEnumName(typePrefix, name, values, static):
+ '''
+ Determine if a given enumeration name is valid (conforming) given the namespace and typename.
+ '''
+ originalName = name
+ originalTypePrefix = typePrefix
+
+ name = name.lower()
+ typePrefix = typePrefix.lower()
+
+ if ((not static) and name.startswith(typePrefix)) and originalName[0].isupper():
+ pass
+ elif ((not static) and (not name.startswith(typePrefix))):
+ return False, conformanceErrorFormatMap["INVALID_GLOBAL_ENUM_NAME"] % ('"' + originalName + '"', originalTypePrefix)
+ elif (static and name.startswith('_')):
+ pass
+ else:
+ return False, conformanceErrorFormatMap["INVALID_STATIC_ENUM_NAME"] % ('"' + originalName + '"')
+
+ for enumVal in values:
+ if ((not static) and not enumVal.startswith(originalName)):
+ return False, conformanceErrorFormatMap["INVALID_GLOBAL_ENUM_VALUE_NAME"] % ('"' + enumVal + '"', originalName)
+ return True, ""
+
+def getTypedefs(path, source):
+ '''
+ Retrieve the names of typedefs (excluding enums) in a given file by parsing the file for
+ typedef specifications. This walks over every line in the file searching for each one,
+ since we cannot extract enum names nicely using linux tools.
+ '''
+ typedefs = []
+ pathToFile = os.path.join(path, source)
+ if os.path.isfile(pathToFile):
+ fin = open(os.path.join(path, source), 'r')
+ lines = fin.readlines()
+ i = 0 # LC
+ while (i < len(lines)):
+ line = lines[i].strip()
+ if not line.startswith("//"):
+ values = []
+ if "typedef" in line and "enum" not in line: # go to the end of the typedef
+ if "{" in line:
+ while "}" not in line:
+ i = i + 1
+ line = lines[i].strip()
+ name = line.replace("}","").replace(";","").strip()
+ typedefs.append(name)
+ else:
+ splits = line.split(" ")
+ if "struct" in splits[1]:
+ name = splits[3].replace(";","")
+ typedefs.append(name.strip())
+ else:
+ pass
+ i = i + 1
+ return typedefs
+
+def getEnumerations(path, source):
+ '''
+ Retrieve the names of enumerations in a given file by parsing the file for enum specifications.
+ This walks over every line in the file searching for enums, since we cannot extract enum names
+ nicely using linux tools.
+ '''
+ enums = []
+ pathToFile = os.path.join(path, source)
+ if os.path.isfile(pathToFile):
+ fin = open(os.path.join(path, source), 'r')
+ lines = fin.readlines()
+ i = 0 # LC
+ while (i < len(lines)):
+ line = lines[i].strip()
+ if not line.startswith("//"):
+ values = []
+ if "typedef enum" in line: # go to the end of the enumeration
+ while (i + 1 < len(lines) and line.find("}") < 0):
+ i = i + 1
+ line = lines[i].strip()
+ values.append(line) # append each string value
+ if (line.find("}") >= 0):
+ name = line.replace("}","").replace(";","")
+ values.pop(len(values) - 1)
+ enums.append((name.strip(), values))
+ i = i + 1
+ return enums
+
+def getTypedefsFromFiles(fileInfoList):
+ '''
+ Get the typedefs from each file in the fileInfoList.
+
+ Each element in fileInfoList is a tuple of the form (path, filename, staticTag),
+ where staticTag is a flag used to indicate if the typedefs in said file should
+ be treated as static.
+ '''
+ allTypedefs = []
+ for (path, fileName, staticTag) in fileInfoList:
+ typedefs = getTypedefs(path, fileName)
+ for typedef in typedefs:
+ allTypedefs.append((typedef, staticTag))
+ return allTypedefs
+
+def getEnumerationsFromFiles(fileInfoList):
+ '''
+ Get the enums from each file in the fileInfoList.
+
+ Each element in fileInfoList is a tuple of the form (path, filename, staticTag),
+ where staticTag is a flag used to indicate if the enums in said file should
+ be treated as static.
+ '''
+ allEnums = []
+ for (path, fileName, staticTag) in fileInfoList:
+ enums = getEnumerations(path, fileName)
+ for (enumName, values) in enums:
+ allEnums.append((enumName, values, staticTag))
+ return allEnums
+
+class FunctionConformanceContainer():
+ def __init__(self, module):
+ self.path = module.getModulePath()
+ self.module = module
+ self.failedFunctions = []
+ self.passedFunctions = []
+
+ if (len(self.path) > 0):
+ self.fullPath = self.path + os.sep + module.getCSourceName()
+ else:
+ self.fullPath = module.getCSourceName()
+
+ self.computeConformance()
+
+ def computeConformance(self):
+ functionDictionary = {}
+ objectFileName = self.module.getPathToObjectFile()
+ sourceFileName = os.path.join(self.path, self.module.getCSourceName())
+ temp = objectFileName
+ if '.a' in temp: # If this is a path into an archive
+ temp = temp.split('(')[0]
+ if not os.path.isfile(temp):
+ raise NoObjectFileException("You must compile " + str(sourceFileName) + " to generate a corresponding object or provide a special object file path")
+
+ try:
+ functionDictionary = getDarwinTestableFunctions(objectFileName)
+ except:
+ raise Exception("You must compile " + str(sourceFileName) + " to generate a corresponding object or provide a special object file path")
+
+ namespace = self.module.getNamespace()
+ modulePrefix = self.module.getModulePrefix()
+
+ # Find all passing/failing functions
+ if (namespace != None and modulePrefix != None):
+ for scope in functionDictionary:
+ for functionName in functionDictionary[scope]:
+ isValid, reason = isValidFunctionName(namespace, modulePrefix, functionName, scope)
+ if isValid:
+ self.addPassedFunction(functionName)
+ else:
+ self.addFailedFunction(functionName, reason)
+
+ def containsMainFunction(self):
+ for (functionName, reason) in self.failedFunctions:
+ if (functionName.strip() == "main" or functionName.strip().startswith("main")):
+ return True
+ for functionName in self.passedFunctions:
+ if (functionName.strip() == "main" or functionName.strip().startswith("main")):
+ return True
+ return False
+
+ @staticmethod
+ def getType():
+ return "function-names"
+
+ def addFailedFunction(self, function, reason):
+ self.failedFunctions.append((function, reason))
+
+ def getFailedFunctions(self):
+ return self.failedFunctions
+
+ def addPassedFunction(self, function):
+ self.passedFunctions.append(function)
+
+ def getPassedFunctions(self):
+ return self.passedFunctions
+
+ def analyzeConformance(self):
+ '''
+ Convert the raw pass/fail function results into a set of individual
+ data points (finegrain results) and overall percentage.
+ '''
+ numPassed = len(self.passedFunctions)
+ numFailed = len(self.failedFunctions)
+
+ self.percentage = 100.0
+ self.points = []
+
+ if (numPassed + numFailed > 0): # skip invalid entries
+ self.percentage = float(float(numPassed) / float(numFailed + numPassed)) * 100.0
+
+ # Data point schema:
+ # namespace, moduleName, targetName, topic, line, col, score
+ for fname in self.passedFunctions:
+ data = ["function-name", fname, 100.0]
+ self.points.append(data)
+
+ for (fname, reason) in self.failedFunctions:
+ data = ["function-name", fname, reason, 0.0]
+ self.points.append(data)
+
+ def getNumberOfPassed(self):
+ return len(self.passedFunctions)
+
+ def getNumberOfFailed(self):
+ return len(self.failedFunctions)
+
+ def totalCSV(self):
+ return tuplesListToCSV(map(lambda point : [self.fullPath] + point, self.points))
+
+ def totalText(self, distribution):
+ formattedLines = tuplesListToPrettyText(self.points, distribution)
+ return map(lambda formattedLine : self.fullPath + " " + formattedLine, formattedLines)
+
+ def summaryCSV(self):
+ line = [(self.getType(), self.percentage)]
+ return tuplesListToCSV(line)
+
+ def summaryText(self, distribution):
+ line = [(self.getType(), self.percentage)]
+ return tuplesListToPrettyText(line, distribution)
+
+ def getScore(self):
+ return (self.getType(), self.percentage)
+
+
+class EnumConformanceContainer():
+ def __init__(self, module):
+ self.path = module.getModulePath()
+ self.module = module
+ self.failedEnums = []
+ self.passedEnums = []
+
+ if (len(self.path) > 0):
+ self.fullPath = self.path + os.sep + module.getCSourceName()
+ else:
+ self.fullPath = module.getCSourceName()
+
+ self.computeConformance()
+
+ def computeConformance(self):
+ sourceFileName = self.module.getCSourceName()
+ headerFileName = self.module.getCHeaderName()
+
+ enums = getEnumerationsFromFiles([(self.path, sourceFileName, True), (self.path, headerFileName, False)])
+ modulePrefix = self.module.getModulePrefix()
+ if (modulePrefix != None):
+ for (enumName, values, staticTag) in enums:
+ isValid, reason = isValidEnumName(modulePrefix, enumName, values, staticTag)
+ if isValid:
+ self.addPassedEnum(enumName)
+ else:
+ self.addFailedEnum(enumName, reason)
+
+ @staticmethod
+ def getType():
+ return "enum-names"
+
+ def addFailedEnum(self, enum, reason):
+ self.failedEnums.append((enum, reason))
+
+ def getFailedEnums(self):
+ return self.failedEnums
+
+ def addPassedEnum(self, enum):
+ self.passedEnums.append(enum)
+
+ def getPassedEnums(self):
+ return self.passedEnums
+
+ def analyzeConformance(self):
+ '''
+ Convert the raw pass/fail enum results into a set of individual
+ data points (finegrain results) and overall percentage.
+ '''
+ self.enumPercentage = 100.0
+ self.points = []
+ numPassed = len(self.passedEnums)
+ numFailed = len(self.failedEnums)
+
+ if (numPassed + numFailed > 0):
+ self.enumPercentage = float((float(numPassed) / float(numPassed + numFailed)) * 100)
+
+ for ename in self.passedEnums:
+ data = ["enum-name", ename, 100.0]
+ self.points.append(data)
+
+ for (ename, reason) in self.failedEnums:
+ data = ["enum-name", ename, reason, 0.0]
+ self.points.append(data)
+
+ def getNumberOfPassed(self):
+ return len(self.passedEnums)
+
+ def getNumberOfFailed(self):
+ return len(self.failedEnums)
+
+ def totalCSV(self):
+ return tuplesListToCSV(map(lambda point : [self.fullPath] + point, self.points))
+
+ def totalText(self, distribution):
+ formattedLines = tuplesListToPrettyText(self.points, distribution)
+ return map(lambda formattedLine : self.fullPath + " " + formattedLine, formattedLines)
+
+ def summaryCSV(self):
+ line = [(self.getType(), self.enumPercentage)]
+ return tuplesListToCSV(line)
+
+ def summaryText(self, distribution):
+ line = [(self.getType(), self.enumPercentage)]
+ return tuplesListToPrettyText(line, distribution)
+
+ def getScore(self):
+ return (self.getType(), self.enumPercentage)
+
+class TypedefConformanceContainer():
+ def __init__(self, module):
+ self.path = module.getModulePath()
+ self.module = module
+ self.failedTypedefs = []
+ self.passedTypedefs = []
+
+ if (len(self.path) > 0):
+ self.fullPath = self.path + os.sep + module.getCSourceName()
+ else:
+ self.fullPath = module.getCSourceName()
+
+ self.computeConformance()
+
+ def computeConformance(self):
+ sourceFileName = self.module.getCSourceName()
+ headerFileName = self.module.getCHeaderName()
+
+ typedefs = getTypedefsFromFiles([(self.path, sourceFileName, True), (self.path, headerFileName, False)])
+
+ modulePrefix = self.module.getModulePrefix()
+ if (modulePrefix != None):
+ for (typedefName, staticTag) in typedefs:
+ isValid, reason = isValidTypedefName(modulePrefix, typedefName, staticTag)
+ if isValid:
+ self.addPassedTypedef(typedefName)
+ else:
+ self.addFailedTypedef(typedefName, reason)
+
+ @staticmethod
+ def getType():
+ return "typedef-names"
+
+ def addFailedTypedef(self, typedef, reason):
+ self.failedTypedefs.append((typedef, reason))
+
+ def getFailedTypedefs(self):
+ return self.failedTypedefs
+
+ def addPassedTypedef(self, typedef):
+ self.passedTypedefs.append(typedef)
+
+ def getPassedTypedefs(self):
+ return self.passedTypedefs
+
+ def analyzeConformance(self):
+ '''
+ Convert the raw pass/fail typedef results into a set of individual
+ data points (finegrain results) and overall percentage.
+ '''
+ self.points = []
+ self.typedefPercentage = 100.0
+ numPassed = len(self.passedTypedefs)
+ numFailed = len(self.failedTypedefs)
+ if (numPassed + numFailed > 0):
+ self.typedefPercentage = float(float(numPassed) / float(numFailed + numPassed)) * 100
+
+ for tName in self.passedTypedefs:
+ data = ["typedef-name", tName, 100.0]
+ self.points.append(data)
+
+ for (tName, reason) in self.failedTypedefs:
+ data = ["typedef-name", tName, reason, 0.0]
+ self.points.append(data)
+
+ def getNumberOfPassed(self):
+ return len(self.passedTypedefs)
+
+ def getNumberOfFailed(self):
+ return len(self.failedTypedefs)
+
+ def totalCSV(self):
+ return tuplesListToCSV(map(lambda point : [self.fullPath] + point, self.points))
+
+ def totalText(self, distribution):
+ formattedLines = tuplesListToPrettyText(self.points, distribution)
+ return map(lambda formattedLine : self.fullPath + " " + formattedLine, formattedLines)
+
+ def summaryCSV(self):
+ line = [(self.getType(), self.typedefPercentage)]
+ return tuplesListToCSV(line)
+
+ def summaryText(self, distribution):
+ line = [(self.getType(), self.typedefPercentage)]
+ return tuplesListToPrettyText(line, distribution)
+
+ def getScore(self):
+ return (self.getType(), self.typedefPercentage)
+
+class ModuleConformanceContainer():
+ '''
+ This conformance container stores a collection of individual type naming
+ conformance results within a particular module, and uses the information
+ contained therein to provide total finegrain and summarized
+ results of the conformance results for each type.
+ '''
+
+ def __init__(self, module):
+ self.conformanceContainers = []
+ self.path = module.getModulePath()
+ self.module = module
+ self.validName = False
+ self.process = True
+
+ if (len(self.path) > 0):
+ self.fullPath = self.path + os.sep + module.getCSourceName()
+ else:
+ self.fullPath = module.getCSourceName()
+
+ def setProcess(self, value):
+ self.process = value
+
+ def processModule(self):
+ return self.process
+
+ def addConformanceContainer(self, complianceContainer):
+ self.conformanceContainers.append(complianceContainer)
+
+ def analyzeConformance(self):
+ for container in self.conformanceContainers:
+ container.analyzeConformance()
+
+ def getNumberOfPassed(self):
+ tuples = []
+ for container in self.conformanceContainers:
+ tuples.append((container.getType(), container.getNumberOfPassed()))
+ return tuples # list of (topic, # of passed)
+
+ def getNumberOfFailed(self):
+ tuples = []
+ for container in self.conformanceContainers:
+ tuples.append((container.getType(), container.getNumberOfFailed()))
+ return tuples # list of (topic, # of failed)
+
+ def totalCSV(self):
+ csvTuples = []
+ for container in self.conformanceContainers:
+ csvTuples = csvTuples + container.totalCSV()
+ return csvTuples
+
+ def totalText(self, distribution):
+ textTuples = []
+ for container in self.conformanceContainers:
+ textTuples = textTuples + container.totalText(distribution)
+ return textTuples
+
+ def summaryCSV(self):
+ singleTuple = [self.fullPath]
+ for container in self.conformanceContainers:
+ csvGroup = container.summaryCSV()
+ singleTuple = singleTuple + [csvGroup[-1]]
+ return tuplesListToCSV([tuple(singleTuple)])
+
+ def summaryText(self, distribution, divider=' '):
+ formattedLine = self.fullPath
+ for container in self.conformanceContainers:
+ lineGroup = container.summaryText(distribution)[0].split(" ")
+ formattedLine = formattedLine + divider + lineGroup[-2] + ' ' + lineGroup[-1]
+ return [formattedLine]
+
+ def getScores(self):
+ scores = {}
+ for container in self.conformanceContainers:
+ scoreKey, scoreVal = container.getScore()
+ scores[scoreKey] = scoreVal
+ return scores
+
+class ModuleSetConformanceContainer():
+ '''
+ This conformance container stores a collection of individual module naming
+ conformance results, and uses the information contained therein to provide
+ summaries of conformance results.
+ '''
+
+ def __init__(self):
+ self.conformanceList = []
+
+ def addConformanceContainer(self, container):
+ self.conformanceList.append(container)
+
+ def analyzeConformance(self):
+ passed = {} # passed type-number bucket
+ failed = {} # failed type-number bucket
+
+ for container in self.conformanceList:
+ passedSet = container.getNumberOfPassed()
+ for (conformanceType, number) in passedSet:
+ if (conformanceType in passed):
+ passed[conformanceType] = passed[conformanceType] + number
+ else:
+ passed[conformanceType] = number
+ failedSet = container.getNumberOfFailed()
+ for (conformanceType, number) in failedSet:
+ if (conformanceType in failed):
+ failed[conformanceType] = failed[conformanceType] + number
+ else:
+ failed[conformanceType] = number
+
+ self.typeConformancePercentages = {}
+ for conformanceType in passed:
+ total = passed[conformanceType] + failed[conformanceType]
+ percentage = 100.0
+ if (total > 0):
+ percentage = (float(passed[conformanceType]) / float(total)) * 100.0
+ self.typeConformancePercentages[conformanceType] = percentage
+
+ def summaryCSV(self):
+ collatedTuple = ["average-scores"]
+ for conformanceType in self.typeConformancePercentages:
+ collatedTuple.append(conformanceType) # append type
+ collatedTuple.append(self.typeConformancePercentages[conformanceType]) # append percentage
+ return tuplesListToCSV([tuple(collatedTuple)])
+
+ def summaryText(self, distribution):
+ formattedLine = "average-scores"
+ for conformanceType in self.typeConformancePercentages:
+ prettyTypeText = tuplesListToPrettyText([(conformanceType, self.typeConformancePercentages[conformanceType])])[0]
+ formattedLine = formattedLine + " " + prettyTypeText
+ return [formattedLine]
+
+def computeModuleNameConformance(module):
+ '''
+ Compute the module name conformance. There is no container for this result
+ since it's a simple boolean.
+ '''
+ namespace = module.getNamespace()
+ moduleName = module.getModuleName()
+ typeName = module.getTypeName()
+
+ if (namespace != None and moduleName != None and typeName != None):
+ return isValidModuleName(namespace, typeName, moduleName)
+ else:
+ return False
+
+def computeModuleConformance(module):
+ '''
+ Compute the naming conformance results for an entire module,
+ which includes conformance results for all types contained therein.
+ '''
+ moduleContainer = ModuleConformanceContainer(module)
+
+ # Get the compliance results for functions, memorizing whether or not a main function was seen
+ functionContainer = FunctionConformanceContainer(module)
+ moduleContainer.addConformanceContainer(functionContainer)
+ moduleContainer.setProcess(not functionContainer.containsMainFunction())
+
+ # Now handle enums, typedefs, etc.
+ moduleContainer.addConformanceContainer(EnumConformanceContainer(module))
+ moduleContainer.addConformanceContainer(TypedefConformanceContainer(module))
+ moduleContainer.setValidName = computeModuleNameConformance(module)
+
+ # Now that we have the data, run over it to generate the results
+ moduleContainer.analyzeConformance()
+
+ return moduleContainer
+
+def getConformanceHeaders():
+ headers = [FunctionConformanceContainer.getType(), EnumConformanceContainer.getType(), TypedefConformanceContainer.getType()]
+ return headers
+
+def gradeAndPrint(targets, objectDirs, problemsOnly=False, printPrefix=""):
+ if len(targets) < 1:
+ print "No Files To Grade"
+ return
+
+ distribution = [99, 90]
+ maxFileNameLength = max(max(map(lambda target: len(target), targets)), len("File Name"))
+
+ moduleConformanceSet = ModuleSetConformanceContainer()
+ headers = getConformanceHeaders()
+ pformat = '{prefix}{:<{maxFileNameLength}}'
+ nformat = pformat
+ for header in headers:
+ nformat = nformat + '{:>15}'
+ print nformat.format('File Name', *headers, prefix=printPrefix, maxFileNameLength=maxFileNameLength)
+
+
+ for target in targets:
+ module = Module(target, objectDirs)
+ if module.isTestSourceName():
+ continue
+ fileNamePrefix = module.getModuleName()
+ path = module.getModulePath()
+ try:
+ moduleConformance = computeModuleConformance(module)
+ if not moduleConformance.processModule():
+ pass
+ else:
+ moduleConformanceSet.addConformanceContainer(moduleConformance)
+ scores = moduleConformance.getScores()
+ minScore = 100.0
+ for key in scores:
+ score = scores[key]
+ if score < minScore:
+ minScore = score
+ scores[key] = '%3.1f'%score
+ if problemsOnly and minScore == 100.0:
+ continue
+ printVals=[]
+ for hval in headers:
+ score = 'N/A'
+ if hval in scores:
+ score = scores[hval]
+ printVals.append(score)
+ line = nformat.format(target, *printVals, prefix=printPrefix, maxFileNameLength=maxFileNameLength)
+ LongBow.scorePrinter(distribution, minScore, line)
+ except NoObjectFileException as e:
+ eformat = pformat + "Could Not Grade: No .o file found for file"
+ line = eformat.format(target, prefix=printPrefix, maxFileNameLength=maxFileNameLength, msg=e)
+ print LongBow.buildRed(line)
+ pass
+ except Exception as e:
+ eformat = pformat + "Could Not Grade: {msg}"
+ line = eformat.format(target, prefix=printPrefix, maxFileNameLength=maxFileNameLength, msg=e)
+ print LongBow.buildRed(line)
+ pass
+ moduleConformanceSet.analyzeConformance()
+
+
+def commandLineMain(args, targets, objectDir):
+ distribution = eval(args.distribution)
+ moduleConformanceSet = ModuleSetConformanceContainer()
+
+ summary = args.summary
+ average = args.average
+ finegrain = args.finegrain
+ if not (summary or average or finegrain):
+ summary = True
+
+ objectDirs = [objectDir]
+ for i in range(len(targets)):
+ module = Module(targets[i], objectDirs)
+ prefix = module.getModuleName()
+ path = module.getModulePath()
+
+ tb = None
+ try:
+ moduleConformance = computeModuleConformance(module)
+ if not moduleConformance.processModule():
+ print >> sys.stderr, "Skipping module " + str(prefix) + ": contains a `main` function"
+ else:
+ moduleConformanceSet.addConformanceContainer(moduleConformance)
+
+ if summary:
+ if args.output == "text":
+ writeListToStream(moduleConformance.summaryText(distribution), sys.stdout)
+ else:
+ writeListToStream(moduleConformance.summaryCSV(), sys.stdout)
+
+ if finegrain:
+ if args.output == "text":
+ writeListToStream(moduleConformance.totalText(distribution), sys.stdout)
+ else:
+ writeListToStream(moduleConformance.totalCSV(), sys.stdout)
+
+ except Exception as e:
+ tb = traceback.format_exc()
+ print >> sys.stderr, "Error: can't analyze conformance of " + os.path.join(path, prefix) + ": " + str(e)
+ finally:
+ if tb != None and args.trace:
+ print tb
+ pass
+
+ moduleConformanceSet.analyzeConformance()
+ if average:
+ if args.output == "text":
+ writeListToStream(moduleConformanceSet.summaryText(distribution), sys.stdout)
+ else:
+ writeListToStream(moduleConformanceSet.summaryCSV(), sys.stdout)
diff --git a/longbow/src/python/site-packages/longbow/StyleReport.py b/longbow/src/python/site-packages/longbow/StyleReport.py
new file mode 100755
index 00000000..7e8d72e0
--- /dev/null
+++ b/longbow/src/python/site-packages/longbow/StyleReport.py
@@ -0,0 +1,382 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+
+import sys
+import os
+import tempfile
+import subprocess
+import difflib
+import csv
+import argparse
+
+import LongBow
+import ANSITerm
+import FileUtil
+import pprint
+
+def getExemplar(fileName, command, config):
+ """Create the exemplar formatted file into memory as a string"""
+
+ with open(fileName) as inputFile:
+ result = subprocess.check_output([command, "-q", "-c", config], stdin=inputFile)
+ return result;
+
+
+def diff(exemplar, fileName):
+ d = difflib.Differ()
+ differ = d.compare(exemplar.splitlines(), fileName.splitlines())
+ return differ
+
+
+class Ratchet:
+ def __init__(self):
+ self.currentValue = 0
+ self.signal = 0
+
+ def value(self):
+ return self.currentValue
+
+ def toggle(self, signal):
+ if self.signal == "-":
+ if signal == "-":
+ self.currentValue = self.currentValue + 1
+ elif signal == "?":
+ self.currentValue = self.currentValue + 1
+ self.signal = 0
+ else:
+ self.currentValue = self.currentValue + 1
+ self.signal = 0
+ pass
+ elif self.signal == "+":
+ if signal == "-":
+ self.currentValue = self.currentValue + 1
+ elif signal == "?":
+ self.currentValue = self.currentValue + 1
+ self.signal = 0
+ else:
+ self.currentValue = self.currentValue + 1
+ self.signal = 0
+ pass
+ else:
+ self.signal = signal;
+
+ return self.currentValue
+
+
+def computeNonCompliantLines(differ):
+ lines = 0
+ changes = Ratchet()
+
+ for l in differ:
+ if l.startswith('-'):
+ changes.toggle(l[0])
+ lines = lines - 1
+ elif l.startswith('+'):
+ changes.toggle(l[0])
+ lines = lines + 1
+ elif l.startswith('?'):
+ pass
+ elif l.startswith(' '):
+ lines = lines +1
+ else:
+ print "What is this:", l
+
+ return changes.value()
+
+
+def reportWhy(differ):
+ print '\n'.join(diff)
+ return
+
+
+class SyntaxCompliance:
+ def __init__(self, fileName, exemplarCommand, exemplarConfig):
+ self.fileName = fileName
+ self.nonCompliantLines = 0
+ self.score = 0
+ self.exemplarCommand = exemplarCommand
+ self.exemplarConfig = exemplarConfig
+ try:
+ self.fileData = FileUtil.readFileString(self.fileName)
+ self.totalLines = len(self.fileData.splitlines())
+ except IOError, e:
+ print >> sys.stderr, e
+ sys.exit(1)
+ pass
+
+ def check(self):
+ self.exemplarData = getExemplar(self.fileName, self.exemplarCommand, self.exemplarConfig)
+ differ = diff(self.fileData, self.exemplarData)
+
+ self.nonCompliantLines = computeNonCompliantLines(differ)
+
+ return self
+
+ def report(self):
+ result = { "fileName" : self.fileName,
+ "label": "style",
+ "score": self.getScore(),
+ "totalLines" : self.getTotalLines(),
+ "nonCompliantLines" : self.getNonCompliantLines()
+ }
+ return result
+
+ def getFileName(self):
+ return self.fileName
+
+ def getExemplarCommand(self):
+ return self.exemplarCommand;
+
+ def getExemplarConfig(self):
+ return self.exemplarConfig;
+
+ def getScore(self):
+ result = 0
+ try:
+ result = int(100 * (1.0 - (float(self.getNonCompliantLines()) / float(self.getTotalLines()))))
+ except ZeroDivisionError:
+ pass
+ return result
+
+ def getTotalLines(self):
+ return self.totalLines
+
+ def getNonCompliantLines(self):
+ return self.nonCompliantLines
+
+ def explain(self):
+ self.exemplarData = getExemplar(self.fileName, self.exemplarCommand, self.exemplarConfig)
+ differ = diff(self.fileData, self.exemplarData)
+
+ ansiTerm = ANSITerm.ANSITerm()
+
+ for l in differ:
+ if l[0] == '-':
+ ansiTerm.printColorized("red", l)
+ elif l[0] == '+':
+ ansiTerm.printColorized("green", l)
+ elif l[0] == '?':
+ ansiTerm.printColorized("yellow", l[0:len(l)-1])
+ else:
+ print l
+ pass
+ return
+
+
+def csvScore(distribution, report):
+ string = "style,%s,%d,%d,%.2f" % (report["fileName"], report["totalLines"], report["nonCompliantLines"], report["score"])
+ LongBow.scorePrinter(distribution, report["score"], string)
+ return
+
+
+def csvAverage(distribution, complianceList):
+ scores = map(lambda target: target.getScore(), complianceList)
+ sum = reduce(lambda sum, score : sum + score, scores)
+ value = float(sum) / float(len(complianceList))
+ LongBow.scorePrinter(distribution, value, "%.2f" % (value))
+ return
+
+
+def csvTotal(distribution, complianceList):
+ totalLines = reduce(lambda sum, x: sum + x, map(lambda element : element.getTotalLines(), complianceList))
+ totalNonCompliantLines = reduce(lambda sum, x: sum + x, map(lambda element : element.getNonCompliantLines(), complianceList))
+ value = 100.0 - (100.0 * float(totalNonCompliantLines) / float(totalLines))
+ LongBow.scorePrinter(distribution, value, "%.2f" % (value))
+ return
+
+
+def csvSummary(distribution, complianceList):
+ map(lambda target: csvScore(distribution, target.report()), complianceList)
+ return
+
+
+def textScore(distribution, report, maxFileNameLength, prefix=""):
+ '''
+
+ '''
+ format = "%s%-*s %6d %6d %6.2f"
+ string = format % (prefix, maxFileNameLength, report["fileName"], report["totalLines"], report["nonCompliantLines"], report["score"])
+ LongBow.scorePrinter(distribution, report["score"], string)
+ return
+
+
+def textAverage(distribution, complianceList):
+ scores = map(lambda target: target.getScore(), complianceList)
+ sum = reduce(lambda sum, score : sum + score, scores)
+ value = float(sum) / float(len(complianceList))
+ LongBow.scorePrinter(distribution, value, "%.2f" % (value))
+ return
+
+
+def textTotal(distribution, complianceList):
+ totalLines = reduce(lambda sum, x: sum + x, map(lambda element : element.getTotalLines(), complianceList))
+ totalNonCompliantLines = reduce(lambda sum, x: sum + x, map(lambda element : element.getNonCompliantLines(), complianceList))
+ value = 100.0 - (100.0 * float(totalNonCompliantLines) / float(totalLines))
+ LongBow.scorePrinter(distribution, value, "%.2f" % (value))
+ return
+
+
+def textSummary(distribution, complianceList, prefix=""):
+ if len(complianceList) > 0:
+ maxFileNameLength = max(max(map(lambda target: len(target.getFileName()), complianceList)), len("File Name"))
+
+ print "%s%-*s %6s %6s %6s" % (prefix, maxFileNameLength, "File Name", "Lines", "Errors", "Score")
+ map(lambda target: textScore(distribution, target.report(), maxFileNameLength, prefix), complianceList)
+
+ return
+
+
+def textVisual(complianceList):
+ map(lambda target: target.explain(), complianceList)
+ return
+
+
+def openDiff(sourceFile, exemplarCommand, exemplarConfig):
+ exemplar = getExemplar(sourceFile, exemplarCommand, exemplarConfig);
+ temporaryExemplarFile = tempfile.NamedTemporaryFile(suffix=".c", delete=False)
+ try:
+ with open(temporaryExemplarFile.name, "w") as exemplarOutput:
+ exemplarOutput.write(exemplar)
+
+ subprocess.check_output(["opendiff", sourceFile, temporaryExemplarFile.name, "-merge", sourceFile])
+ finally:
+ pass
+
+ return
+
+
+def displaySummary(args, complianceList):
+ distribution = eval(args.distribution)
+
+ if args.output == "text":
+ textSummary(distribution, complianceList)
+ elif args.output == "gui":
+ textSummary(distribution, complianceList)
+ else:
+ csvSummary(distribution, complianceList)
+ return
+
+
+def displayAverage(args, complianceList):
+
+ distribution = eval(args.distribution)
+
+ if args.output == "text":
+ textAverage(distribution, complianceList)
+ elif args.output == "gui":
+ textAverage(distribution, complianceList)
+ else:
+ csvAverage(distribution, complianceList)
+ return
+
+
+def displayTotal(args, complianceList):
+ distribution = eval(args.distribution)
+
+ if args.output == "text":
+ textTotal(distribution, complianceList)
+ elif args.output == "gui":
+ textTotal(distribution, complianceList)
+ else:
+ csvTotal(distribution, complianceList)
+ return
+
+
+def guiVisual(args, complianceList):
+ map(lambda target: openDiff(target.getFileName(), target.getExemplarCommand(), target.getExemplarConfig()), complianceList)
+ return
+
+
+def displayVisual(args, complianceList):
+ if args.output == "text":
+ textVisual(complianceList)
+ elif args.output == "gui":
+ guiVisual(args, complianceList)
+ else:
+ print >> sys.stderr, "Unsupported output format '%s'. Expected 'text' or 'gui'." % (args.output)
+ sys.exit(1)
+ return
+
+
+def sortComplianceList(args, complianceList):
+
+ sorter = {
+ "name" : { "function" : lambda k: k.getFileName(), "reverse" : False },
+ "descending-name" : { "function" : lambda k: k.getFileName(), "reverse" : True },
+ "score" : { "function" : lambda k: k.getScore(), "reverse" : False },
+ "descending-score" : { "function" : lambda k: k.getScore(), "reverse" : True },
+ "size" : { "function" : lambda k: k.getTotalLines(), "reverse" : False },
+ "descending-size" : { "function" : lambda k: k.getTotalLines(), "reverse" : True },
+ }
+
+ if args.key == "help":
+ print >> sys.stderr, "Supported sort keys:"
+ map(lambda k: sys.stderr.write("'" + k + "' "), sorted(sorter))
+ print
+ sys.exit(1)
+
+ if args.key in sorter:
+ complianceList = sorted(complianceList, key=sorter[args.key]["function"], reverse=sorter[args.key]["reverse"])
+ else:
+ print >> sys.stderr, "Unsupported sort key '%s'. Type '--key help'" % (args.key)
+ sys.exit(1)
+
+ return complianceList
+
+
+def exclude(args, complianceList):
+ excluded = map(lambda token : token.strip(), args.exclude.split(","))
+ complianceList = filter(lambda entry: LongBow.score(eval(args.distribution), entry.getScore()) not in excluded, complianceList)
+
+ return complianceList
+
+
+def gradeAndPrint(targets, exemplarCommand, exemplarConfig, problemsOnly=False, prefix=""):
+ complianceList = []
+ problemList = []
+ for target in targets:
+ try:
+ complianceList.append(SyntaxCompliance(target, exemplarCommand, exemplarConfig).check())
+ except:
+ problemList.append(target)
+ pass
+ complianceList = sorted(complianceList, key=lambda k: k.getFileName())
+ if problemsOnly:
+ complianceList = filter(lambda entry: entry.getScore() < 100, complianceList)
+ distribution=[99,90]
+ textSummary(distribution, complianceList, prefix)
+
+ for target in problemList:
+ print LongBow.buildRed("%s%s could not be evaluated" % (prefix, target))
+
+
+def commandLineMain(args, targets, exemplarCommand, exemplarConfig):
+ complianceList = map(lambda target: SyntaxCompliance(target, exemplarCommand, exemplarConfig).check(), targets)
+
+ complianceList = sortComplianceList(args, complianceList)
+
+ complianceList = exclude(args, complianceList)
+
+ if args.summary:
+ displaySummary(args, complianceList)
+ elif args.average:
+ displayAverage(args, complianceList)
+ elif args.total:
+ displayTotal(args, complianceList)
+ elif args.visual:
+ displayVisual(args, complianceList)
+ return
diff --git a/longbow/src/python/site-packages/longbow/SymbolTable.py b/longbow/src/python/site-packages/longbow/SymbolTable.py
new file mode 100755
index 00000000..20a909d7
--- /dev/null
+++ b/longbow/src/python/site-packages/longbow/SymbolTable.py
@@ -0,0 +1,87 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+import os
+import subprocess
+import re
+import sys
+import pprint
+
+def parseLocation(location):
+ token = location.split("[")
+ objectFileName = location
+
+ if len(token) > 1:
+ libraryName = token[0]
+ objectFileName = token[1].split("]")[0]
+ else:
+ libraryName = None
+
+ objectFileName = objectFileName.split(":")[0]
+ return (libraryName, objectFileName)
+
+def parseDarwinOutput(lines, accumulator = { }):
+
+ for line in lines:
+ token = line.split(" ")
+ fullName = token[0]
+
+ libraryName, objectFileName = parseLocation(token[0])
+ name = token[1]
+ type = token[2]
+ if fullName in accumulator:
+ if type == "U":
+ accumulator[fullName]["undefined"].append({ "name" : name })
+ elif type == "T":
+ accumulator[fullName]["defined"].append({ "name" : name })
+ elif type == "D":
+ accumulator[fullName]["globalData"].append({ "name" : name })
+ else:
+ accumulator[fullName] = { "fullName" : fullName, "libraryName" : libraryName, "objectFileName" : objectFileName, "defined" : [], "undefined" : [], "globalData" : [] }
+
+ return accumulator
+
+def getDarwinSymbolTable(objectFileName, accumulator = { }):
+ command = [ "/usr/bin/nm", "-PAog", objectFileName ]
+
+ output = subprocess.check_output(command)
+ lines = output.splitlines()
+ return parseDarwinOutput(lines, accumulator)
+
+
+def getSymbolTable(objectFileName, accumulator = { }):
+ '''
+ {
+ fullName : { "defined" : list of dictionaries,
+ "undefined": list of dictionaries,
+ "globalData" : list of dictionaries,
+ "libraryName" : string
+ "objectFileName : string
+ },
+ }
+ '''
+ return getDarwinSymbolTable(objectFileName, accumulator)
+
+
+if __name__ == '__main__':
+
+ table = dict()
+ for f in sys.argv:
+ table = getSymbolTable(f, table)
+
+ pp = pprint.PrettyPrinter(indent=4, width=132)
+
+ pp.pprint(table)
diff --git a/longbow/src/python/site-packages/longbow/VocabularyReport.py b/longbow/src/python/site-packages/longbow/VocabularyReport.py
new file mode 100755
index 00000000..5609db11
--- /dev/null
+++ b/longbow/src/python/site-packages/longbow/VocabularyReport.py
@@ -0,0 +1,162 @@
+#! /usr/bin/env python
+# Copyright (c) 2017 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+
+import sys
+import itertools
+
+import LongBow
+
+def computeVocabularyScore(tokenCount):
+ return 100.0
+
+
+def csvFunctionResult(file, function):
+ score = computeVocabularyScore(file.token_count)
+ string = "vocabulary,%s,%s,%d,%d,%.2f" % (file.filename, function.name, function.start_line, function.token_count, score)
+
+ LongBow.scorePrinter([90, 80], score, string)
+ return function.token_count
+
+
+def csvFileVocabulary(file):
+ score = computeVocabularyScore(file.token_count)
+ string = "vocabulary,%s,,,%.2f,%.2f" % (file.filename, file.average_token, score)
+ LongBow.scorePrinter([90, 80], score, string)
+ return
+
+
+def csvFunction(fileInformationList):
+ for fileInformation in fileInformationList:
+ complexities = map(lambda function: csvFunctionResult(fileInformation, function), fileInformation)
+ return
+
+
+def csvSummary(fileInformationList):
+ map(lambda file: csvFileVocabulary(file), fileInformationList)
+ return
+
+
+def textFunctionResult(file, function, maxFileNameLength, maxFunctionNameLength):
+ score = computeVocabularyScore(function.token_count)
+ format = "%-" + str(maxFileNameLength) + "s %-" + str(maxFunctionNameLength) + "s %3d %3d %6.2f"
+ string = format % (file.filename, function.name, function.start_line, function.token_count, score)
+
+ LongBow.scorePrinter([90, 80], score, string)
+ return function.cyclomatic_complexity
+
+
+def textFileVocabulary(file, maxFileNameLength, printFormat=""):
+ score = computeVocabularyScore(file.average_CCN)
+ if printFormat == "":
+ printFormat = "%-" + str(maxFileNameLength) + "s %6.2f %6.2f"
+ string = printFormat % (file.filename, file.average_token, score)
+ LongBow.scorePrinter([90, 80], score, string)
+ return
+
+
+def computeMaxFileNameLength(fileInformationList):
+ result = 0
+ for fileInformation in fileInformationList:
+ if len(fileInformation.filename) > result:
+ result = len(fileInformation.filename)
+ return result
+
+
+def computeMaxFunctionNameLength(fileInformationList):
+ result = 0
+ for fileInformation in fileInformationList:
+ if len(fileInformation.filename) > result:
+ result = len(fileInformation.filename)
+ return result
+
+
+def textFunction(fileInformationList):
+ maxFileNameLength = max(map(lambda fileInformation: len(fileInformation.filename), fileInformationList))
+ maxFunctionNameLength = max(map(lambda fileInformation: max(map(lambda function: len(function.name), fileInformation)), fileInformationList))
+
+ for fileInformation in fileInformationList:
+ complexities = map(lambda function: textFunctionResult(fileInformation, function, maxFileNameLength, maxFunctionNameLength), fileInformation)
+ return
+
+
+def textSummary(fileInformationList, prefix=""):
+ if len(fileInformationList) < 1:
+ print "%sNo Files To Grade" % prefix
+ return
+ maxFileNameLength = max(map(lambda fileInformation: len(fileInformation.filename), fileInformationList))
+ printFormat = prefix + "%-" + str(maxFileNameLength) + "s %10s %6s"
+ print printFormat % ("File Path", "Ave Token", "Score")
+ printFormat = prefix + "%-" + str(maxFileNameLength) + "s %10.2f %6.2f"
+ map(lambda file: textFileVocabulary(file, maxFileNameLength, printFormat), fileInformationList)
+ return
+
+
+def computeAverage(fileInformationList):
+ vocabulary = map(lambda fileInformation : fileInformation.average_token, fileInformationList)
+ sum = reduce(lambda sum, x: sum + x, vocabulary)
+ return float(sum) / float(len(vocabulary))
+
+
+def gradeAndPrint(fileList, hfcca, problemsOnly=False, prefix=""):
+ options, arguments = hfcca.createHfccaCommandLineParser().parse_args(args=["foo"])
+ result = hfcca.analyze(fileList, options)
+
+ # Convert from that iterator to a simple list...
+ fileInformationList = map(lambda x : x, result)
+ if problemsOnly:
+ fileInformationList = filter(lambda item: computeVocabularyScore(item.average_CCN) < 100, fileInformationList)
+
+ textSummary(fileInformationList, prefix)
+
+def commandLineMain(args, hfcca):
+ targets = []
+
+ if args.stdin:
+ for line in sys.stdin:
+ t = line.strip()
+ if (len(t) > 0):
+ targets.append(t)
+ else:
+ targets = args.files
+
+ if (len(targets) == 0):
+ print >> sys.stderr, "Error: target list cannot be empty"
+
+ # If nothing was specified, print the summary as a default
+ if args.summary == False and args.function == False and args.average == False:
+ args.summary = True
+
+ options, arguments = hfcca.createHfccaCommandLineParser().parse_args(args=["VocabularyReport"])
+ result = hfcca.analyze(targets, options)
+
+ # Convert from that iterator to a simple list...
+ fileInformationList = map(lambda x : x, result)
+
+ if args.function:
+ if args.output == "text":
+ textFunction(fileInformationList)
+ else:
+ csvFunction(fileInformationList)
+
+ if args.summary:
+ if args.output == "text":
+ textSummary(fileInformationList)
+ else:
+ csvSummary(fileInformationList)
+
+ if args.average:
+ print "%.2f" % computeAverage(fileInformationList)